From dabf615026ce8dee1e88924fafb9d9c69dba4e86 Mon Sep 17 00:00:00 2001 From: Ramon Perez Date: Fri, 7 Feb 2025 15:45:56 +0100 Subject: [PATCH 1/2] Document example-cnf test cases --- README.md | 59 ++++++------ documentation/testing.md | 193 +++++++++++++++++++++++++++++++++++++ documentation/workflow.png | Bin 0 -> 145439 bytes 3 files changed, 225 insertions(+), 27 deletions(-) create mode 100644 documentation/testing.md create mode 100644 documentation/workflow.png diff --git a/README.md b/README.md index 3817939..d85bb03 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ -Example CNF -============== +# Example CNF [![PR Validation](https://github.com/openshift-kni/example-cnf/actions/workflows/push.yaml/badge.svg)](https://github.com/openshift-kni/example-cnf/actions/workflows/push.yaml) -Example CNF is an OpenShift workload to exercice an SRIOV setup, such as the following: +Example CNF is an OpenShift workload to exercice an SRIOV setup, based on [TestPMD](https://doc.dpdk.org/guides/testpmd_app_ug/intro.html) for traffic forwarding and [TRex](https://trex-tgn.cisco.com/) for traffic generation, such as the following: ![Flow](documentation/network_setup.png) @@ -36,16 +35,25 @@ It is providing the following operators: ![Operator behavior](documentation/cnf-app-mac-operator.png) -You can use them from the [Example CNF Catalog](https://quay.io/repository/rh-nfv-int/nfv-example-cnf-catalog?tab=tags). +You can use them from the [Example CNF Catalog](https://quay.io/repository/rh-nfv-int/nfv-example-cnf-catalog?tab=tags). Image generation is automated with [Github workflows](.github/workflows) in this repo. -How operators are created ------------------------- +## Pre-requirements -The three operators defined in this repository are built with [Operator SDK tool](https://sdk.operatorframework.io/docs/building-operators/). +To run Example CNF, you need to fulfil the following infrastructure-related pre-requirements: + +- OpenShift cluster with +3 worker nodes. +- SR-IOV network operator. +- SriovNetworkNodePolicy and SriovNetwork CRDs. +- Proper configuration in network devices to match the SR-IOV resources definition. +- Performance Profile (Hugepages, CPU Isolation, etc.) + +## How operators are created + +The three operators defined in this repository are built with [Operator SDK tool](https://sdk.operatorframework.io/docs/building-operators/). [Here](https://youtu.be/imF9VGJ1Dd4) you can see how CRD-to-pod conversion works for this kind of operators. We can differentiate between these two cases: -**Ansible-based operators:** +### Ansible-based operators This is the case of testpmd-operator and trex-operator. @@ -68,7 +76,7 @@ $ operator-sdk create api --version v1 --generate-role --group examplecnf --kind $ operator-sdk create api --version v1 --generate-role --group examplecnf --kind TRexConfig ``` -**Go-based operators:** +### Go-based operators This is the case of cnf-app-mac-operator. @@ -118,18 +126,11 @@ To conclude, build the main.go file to check it's working fine: $ go build cmd/main.go ``` -Ansible based automation ------------------------- - -You can use the Ansible playbooks and roles at to automate the use of the Example CNF. - -Pod affinity rules ------------------------- +## Pod affinity rules There are some affinity rules for the deployed pods. In particular, `trexconfig-` and `testpmd-app-` pods are placed in different worker nodes. -SRIOV networks ------------------------- +## SRIOV networks SRIOV networks are required for the setup. In our case, we are using a different SRIOV network per connection, using a different VLAN for each network. @@ -153,8 +154,7 @@ The network schema would be as follows: TRex -- (example-cnf-net1|2) -- CNF Application ``` -Traffic Flow ------------------------- +## Traffic Flow Traffic flow is the following: @@ -168,11 +168,13 @@ Traffic flow is the following: - TRex calculates statistics by comparing the incoming traffic on Port 1 (processed traffic) with the outgoing traffic on Port 0 (original traffic sent by TRex) and vice versa. +## Testing + +Please refer to [the testing docs](documentation/testing.md) to check how to test Example CNF using [Distributed-CI (DCI)](https://docs.distributed-ci.io/). -Network troubleshooting ------------------------- +## Network troubleshooting -Apart from the logs offered by the resources deployed by example-cnf, the `ip` command can also offer some useful network information regarding the statistics of the network interfaces used in the tests. +Apart from the logs offered by the resources deployed by Example CNF, the `ip` command can also offer some useful network information regarding the statistics of the network interfaces used in the tests. For example, by accessing to the worker node where the resources are deployed, and checking the interface where the VFs are created, you can see information like this: @@ -267,14 +269,13 @@ $ ip -s -d link show dev ens2f0 altname enp55s0f0 ``` -Utils ------------------------- +## Utils -Under [utils](utils) folder, you can find some utilities included in example-cnf to extend the functionalities offered by the tool. +Under [utils](utils) folder, you can find some utilities included in Example CNF to extend the functionalities offered by the tool. - [webserver.go](utils/webserver.go): a Golang-based webserver to implement liveness, readiness and startup probes in the container images offered in [testpmd-container-app](testpmd-container-app) and [trex-container-app](trex-container-app) folders. The Makefiles offered in these directories take care of copying the webserver code from the utils directory to each image's directory. - [required-annotations.yaml](utils/required-annotations.yaml): annotations to be appended to the CSVs to pass Preflight's RequiredAnnotations tests. They are appended automatically thanks to the Makefile tasks from each operator. -- [support-images](support_images): projects where you can find the Dockerfile required to build some of the images used as build images by the example-cnf images. These images can be found on quay.io/rh-nfv-int and they are publicly available, you only need credentials to access quay.io. The images can be built with the following commands (you need to run it in a RHEL host with a valid RHEL subscription to be able to download the packages installed in the images, and you need a valid quay.io credentials to push it to quay.io): +- [support-images](support_images): projects where you can find the Dockerfile required to build some of the images used as build images by the Example CNF images. These images can be found on quay.io/rh-nfv-int and they are publicly available, you only need credentials to access quay.io. The images can be built with the following commands (you need to run it in a RHEL host with a valid RHEL subscription to be able to download the packages installed in the images, and you need a valid quay.io credentials to push it to quay.io): ``` # build images @@ -288,3 +289,7 @@ $ podman push quay.io/rh-nfv-int/dpdk-23.11:v0.0.1 $ podman push quay.io/rh-nfv-int/ubi8-base-testpmd:v0.0.1 $ podman push quay.io/rh-nfv-int/ubi8-base-trex:v0.0.1 ``` + +## Acknowledgements + +Please write to telcoci@redhat.com in case you need more information for using and testing Example CNF in the scenarios that have been proposed in this repository. diff --git a/documentation/testing.md b/documentation/testing.md new file mode 100644 index 0000000..ee9c2b5 --- /dev/null +++ b/documentation/testing.md @@ -0,0 +1,193 @@ +# Testing Example CNF + +In this document, we will show you how to test Example CNF using [Distributed-CI (DCI)](https://docs.distributed-ci.io/). + +For this to work, we will assume that we have an OCP cluster up and running that meets the [pre-requirements](../README.md#pre-requirements) to launch Example CNF, and that all DCI tools (`dci-openshift-agent`, `dci-openshift-app-agent` and `dci-pipeline`) are installed in a jumphost server which has access to the OCP cluster. + +You can use the Ansible playbooks and roles at to automate the use of the Example CNF. + +## Pipeline configuration + +To deploy Example CNF, we will use [`dci-pipeline` tool](https://blog.distributed-ci.io/dci-pipeline.html), with the following pipeline configuration (this corresponds to the [baseline scenario](#baseline-scenario) we will present later on, but can be used as base for the rest of scenarios): + +``` +$ cat example-cnf-pipeline.yml +--- +- name: example-cnf + stage: workload + prev_stages: [openshift-upgrade, openshift] + ansible_cfg: /usr/share/dci-openshift-agent/ansible.cfg + ansible_playbook: /usr/share/dci-openshift-app-agent/dci-openshift-app-agent.yml + ansible_inventory: /etc/dci-openshift-app-agent/hosts.yml + configuration: "myqueue" + dci_credentials: ~/.config/dci-pipeline/credentials.yml + ansible_extravars: + dci_cache_dir: /var/lib/dci-pipeline + dci_tags: + - debug + + # Including example-cnf hooks + dci_config_dir: /usr/share/example-cnf-config/testpmd + dci_gits_to_components: + - /usr/share/example-cnf-config + + # Do not delete resources when the job finishes + dci_teardown_on_success: false + dci_teardown_on_failure: false + + # Point to SRIOV config + example_cnf_sriov_file: /usr/share/mycluster-sriov-config.yml + + # Tune example-cnf execution + ## Allow testpmd in reduced mode + ecd_testpmd_reduced_mode: 1 + ## Tune TRexApp parameters + ecd_trex_duration: 120 + ecd_trex_packet_rate: 2mpps + ecd_trex_packet_size: 64 + + # Allow failures in TRex jobs in case we have packet loss because of the data rate we're generating + example_cnf_skip_trex_job_failure: true + + use_previous_topic: true + components: + - nfv-example-cnf-index + inputs: + kubeconfig: kubeconfig_path +``` + +From this pipeline, we can extract the following information: + +- Example CNF is launched on top of a running OpenShift cluster, using `dci-openshift-app-agent` as main Ansible automation. +- Example CNF hooks are downladed in the jumphost from [example-cnf-config](https://github.com/dci-labs/example-cnf-config/tree/master/testpmd) repository, under `/usr/share` folder. +- The deployment is not removed when the DCI job finishes. +- SRIOV config is provided in a YAML file like this one (previously, you would have needed to configure your network to match that configuration in your cluster, so that the worker node's interfaces have the given VLAN configured): + +``` +$ cat mycluster-sriov-config.yml +--- +sriov_network_configs: + - resource: example_cnf_res1 + node_policy: + name: example-cnf-policy1 + device_type: vfio-pci + is_rdma: false + mtu: 9000 + nic_selector: + device_id: 158b + pf_names: + - ens7f0#0-7 + vendor: "8086" + node_selector: + node-role.kubernetes.io/worker: "" + num_vfs: 16 + priority: 99 + - resource: example_cnf_res2 + node_policy: + name: example-cnf-policy2 + device_type: vfio-pci + is_rdma: false + mtu: 9000 + nic_selector: + device_id: 158b + pf_names: + - ens7f0#8-15 + vendor: "8086" + node_selector: + node-role.kubernetes.io/worker: "" + num_vfs: 16 + priority: 99 + - resource: example_cnf_res1 + network: + name: example-cnf-net1 + network_namespace: example-cnf + spoof_chk: "off" + trust: "on" + vlan: 3801 + capabilities: '{"mac": true}' + - resource: example_cnf_res2 + network: + name: example-cnf-net2 + network_namespace: example-cnf + spoof_chk: "off" + trust: "on" + vlan: 3802 + capabilities: '{"mac": true}' +``` + +- Fine tune the parameters for the tests to be launched. We can configure here the following: + + - `ecd_testpmd_reduced_mode`: default value is 0. If it's different than 0, it allows Example CNF to use the reduced mode in the [testpmd-wrapper](../testpmd-container-app/cnfapp/scripts/testpmd-wrapper) script, where only three cores are used on testpmd, and txd/rxd parameters are doubled. + - `ecd_trex_duration`: default value is 120. It is the duration of the TRex run. If setting -1, TRex will run on continuous burst mode. If setting any value here, TRex job will be stopped once this time is reached. This may imply packet loss if using a high packet rate. + - `ecd_trex_packet_rate`: default value is 10kpps. It is the packet rate used by TRex to send traffic, expressed in packets per second (pps). Units are defined in lower case, so 2mpps means 2 megapackets per second (2.000.000 packets/s). + - `ecd_trex_packet_size`: devault value is 64. It is the size of the packets sent by TRex, in bytes. This value, combined with the packet rate, allows you to determine the throughput that is injected by TRex. For example, with 64 B and 2mpps, we would have around `64*8*2*10^6 = 1 Gbps`. + - `example_cnf_skip_trex_job_failure`: default value is false, but since it may happen that, after reaching the duration timeout, there are still packets that are being sent (mostly if using a high throughput, closer to the link data rate), Example CNF may detect packet loss in that case and make the DCI job to fail. To avoid that effect, you can set this parameter to true. + +## Baseline scenario + +The baseline scenario corresponds to this workflow (other scenarios are modifications taken from this baseline workflow): + +![Workflow](workflow.png) + +You can run it with this command: + +``` +$ export KUBECONFIG=/path/to/mycluster/kubeconfig +$ DCI_QUEUE_RESOURCE=mycluster dci-pipeline-schedule example-cnf +``` + +This is an example of a [job](https://www.distributed-ci.io/jobs/57ec2b12-f450-436e-961e-b19912cadb21/jobStates) launched with this pipeline. + +> This job launches more test cases, related to Red Hat certification, that are out of the scope of this documentation. + +### Check the pods + +We can check the pods that have been created after launching the pipeline: + +``` + +``` + +## Troubleshooting mode scenario + +The baseline scenario is a good option to be able to launch Example CNF operators and deploy TRex automatically, being suitable for a CI system loop where the tests are executed N times and then we can extract conclusions from all the results obtained. However, we cannot really interact with either TestPMD or TRex. + +To achieve this goal, we can run Example CNF in troubleshooting mode by just providing some extra parameters to `dci-pipeline-schedule` call. In this way, all Example CNF operators will be created and all pods will keep up and running with all scripts prepared for being launched, but the automation will not take care of launching the test scripts and creating the TRex job, so that we can interact with both TestPMD and TRex to check on-line the behavior and results. + +You can launch this scenario with the following call to `dci-pipeline-schedule`: + +``` +$ export KUBECONFIG=/path/to/mycluster/kubeconfig +$ DCI_QUEUE_RESOURCE=mycluster dci-pipeline-schedule example-cnf +``` + +Here's a [DCI job example](https://www.distributed-ci.io/jobs/67fec9f4-8629-4ca9-8c8f-54ce2e7e85db/jobStates?sort=date) with this troubleshooting mode execution. + +### Check pods + +TBD - https://docs.google.com/document/d/1H2ckIk1OaCFcEdjxFin5QcYf-qpmvEqwJvUUZt4sWIc/edit?tab=t.0#heading=h.63hal0xqwm0t + +## Draining scenario + +### Manual testing + +TBD - https://docs.google.com/document/d/1DDZubnc16FCLPb8xNF2ybWhVbU3q366KmkITa2q1cFQ/edit?tab=t.0#heading=h.63hal0xqwm0t + +### Automation + +## Test Example CNF during upgrades + +## Create a new TRexApp job + +## Remove Example CNF deployment + +You can use the same pipeline from the [baseline scenario](#baseline-scenario) to remove Example CNF from your cluster, in case you didn't set `dci_teardown_on_success|failure` variables to true. + +You can do it with the following call to `dci-pipeline-schedule`: + +``` +$ export KUBECONFIG=/path/to/mycluster/kubeconfig +$ DCI_QUEUE_RESOURCE=mycluster dci-pipeline-schedule example-cnf +``` + +Here's a [DCI job example](https://www.distributed-ci.io/jobs/22a50cd0-6bc6-439c-94af-e401ca467962/jobStates?sort=date) with this cleanup execution. diff --git a/documentation/workflow.png b/documentation/workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..eec85c7588f02918d352b285df82f2a4bee9a1e5 GIT binary patch literal 145439 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%0A9rv;2(5$>V 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 Date: Mon, 10 Feb 2025 17:51:50 +0100 Subject: [PATCH 2/2] Finish testing docs --- documentation/testing.md | 1126 +++++++++++++++++++++++++++++++++++++- 1 file changed, 1116 insertions(+), 10 deletions(-) diff --git a/documentation/testing.md b/documentation/testing.md index ee9c2b5..eccb146 100644 --- a/documentation/testing.md +++ b/documentation/testing.md @@ -62,6 +62,7 @@ From this pipeline, we can extract the following information: - Example CNF hooks are downladed in the jumphost from [example-cnf-config](https://github.com/dci-labs/example-cnf-config/tree/master/testpmd) repository, under `/usr/share` folder. - The deployment is not removed when the DCI job finishes. - SRIOV config is provided in a YAML file like this one (previously, you would have needed to configure your network to match that configuration in your cluster, so that the worker node's interfaces have the given VLAN configured): +- With nfv-example-cnf-index DCI component, we will refer to the software to be used to download Example CNF-related images from Quay.io. Here, we are using the latest version currently available, since we're not pinning the version to use. Here's an example of a [nfv-example-cnf-index DCI component](https://www.distributed-ci.io/topics/b8454f14-ff58-41ad-b31c-00f9e84eff3c/components/fb503d17-57da-4e54-9095-6d2bdd858f24). The `Data` field contains the URL to reach the registry where the images are defined, and the image version is the same that the one used in the component (for this example, v0.3.7-202501202232.2eb6d6d). ``` $ cat mycluster-sriov-config.yml @@ -129,6 +130,8 @@ The baseline scenario corresponds to this workflow (other scenarios are modifica ![Workflow](workflow.png) +This automatically deploys the operators and the pods that allows to test the traffic exchange between TRex and TestPMD. So, by just launching the proposed pipeline, this will be achieved automatically without any manual intervention. Consequently, once the pipeline execution finishes, you can only retrieve execution logs, since the tests have already been executed. + You can run it with this command: ``` @@ -136,7 +139,7 @@ $ export KUBECONFIG=/path/to/mycluster/kubeconfig $ DCI_QUEUE_RESOURCE=mycluster dci-pipeline-schedule example-cnf ``` -This is an example of a [job](https://www.distributed-ci.io/jobs/57ec2b12-f450-436e-961e-b19912cadb21/jobStates) launched with this pipeline. +This is an example of a [job](https://www.distributed-ci.io/jobs/0ae26cc0-41b8-4f1b-86ce-1cbaf3a512b9/jobStates) launched with this pipeline. > This job launches more test cases, related to Red Hat certification, that are out of the scope of this documentation. @@ -145,12 +148,174 @@ This is an example of a [job](https://www.distributed-ci.io/jobs/57ec2b12-f450-4 We can check the pods that have been created after launching the pipeline: ``` +$ oc get pods -n example-cnf +NAME READY STATUS RESTARTS AGE +cnf-app-mac-operator-controller-manager-74498bddcd-96v6q 1/1 Running 0 158m +cnf-app-mac-operator-controller-manager-74498bddcd-s7tj2 1/1 Running 0 159m +job-trex-app-fcs5j 0/1 Completed 0 152m +testpmd-app-66f65bf475-4897b 1/1 Running 0 119m +testpmd-operator-controller-manager-6488b4c774-hctzp 1/1 Running 0 157m +testpmd-operator-controller-manager-6488b4c774-zjhtw 1/1 Running 0 156m +trex-operator-controller-manager-6cdd46d4cd-g7mj6 1/1 Running 0 156m +trex-operator-controller-manager-6cdd46d4cd-jms2t 1/1 Running 0 156m +trexconfig-5865745c74-qstk6 1/1 Running 0 154m +``` + +We can see these pods: + +- Controller manager pods (they're replicated for ensuring high availability) for each operator that is deployed in this scenario. +- `testpmd-app` pod, which corresponds to TestPMD. This launches TestPMD tool, configure and start it automatically, printing statistics every second. +- `trexconfig` pod, which corresponds to TRexServer. This configures TRex to start listening to incoming requests to send traffic to a given target. It also prints statistics regularly. +- `job-trex-app` pod, which corresponds to TRexApp, and it's launched from a Job resource. This provides a data profile to TRex, which then starts sending traffic to the configured destination (i.e. TestPMD), and also prints statistics at the end of the execution, printing the packet loss. + +> In the case of `testpmd-app` pod, the pod you will find after the pipeline execution does not correspond to the `testpmd-app` pod used for exchanging traffic with TRex. This is because, in the proposed hooks, the `testpmd-app` is deleted at the end of the tests to confirm that a new `testpmd-app` pod is created automatically. + +### What is it executed on each data-plane pod? + +The three data-plane pods (`testpmd-app`, `trexconfig` and `job-trex-app`) execute different scripts to configure all the software pieces that involves the traffic exchange between TestPMD and TRex: + +- `testpmd-app`: it runs `/usr/local/bin/example-cnf/testpmd-wrapper`. [This script](../testpmd-container-app/cnfapp/scripts/testpmd-wrapper) retrieves context information to build the command to run `testpmd` command-line tool. In this baseline scenario, once finished, `testpmd` is invoked in auto-start mode, printing the statistics every minute. +- `trexconfig`: it runs `/usr/local/bin/trex-wrapper`. [This script](../trex-container-app/server/scripts/trex-wrapper) takes also some context information to build a config file for TRex, then it launches `_t-rex-64` binary using the generated config file, and printing statistics regularly. This does not launch the traffic generation, since this is done with the TRexApp job. +- `job-trex-app`: it runs `/usr/local/bin/trex-wrapper` (but a different one compared to `trexconfig`). [This script](../trex-container-app/app/scripts/trex-wrapper) triggers a custom Python script that builds the traffic profile, according to the TRex variables provided in the pipeline (duration of the job, packet size, data rate, etc.), and start sending the traffic. If defining a duration, a timeout will be enabled to stop the execution after the given duration, and then statistics will be printed and packet loss will be calculated. If packet loss is equal or less than 0, this means there's no packet loss, else, packet loss is present and the pod status will be different than Completed. + +### What logs should I check? + +In this baseline scenario, everything will be executed once the pipeline execution finishes. To check if the TRexApp job has passed or not, you can take a look at the `job-trex-app` logs and check the end: + +``` +$ oc logs -n example-cnf job-trex-app-fcs5j +... +2025-02-10 05:12:47,525 - run-trex - INFO - CR to be utilized for event creation: {'apiVersion': 'events.k8s.io/v1', 'kind': 'Event', 'metadata': {'name': 'trex-app-1ojxuk', 'namespace': 'example-cnf', 'ownerReferences': [{'apiVersion': 'examplecnf.openshift.io/v1', 'kind': 'TRexApp', 'name': 'trex-app', 'uid': '133af93f-5956-4451-84a2-93627533f0b1', 'controller': True}]}, 'type': 'Normal', 'eventTime': '2025-02-10T05:12:47.505486Z', 'series': {'lastObservedTime': '2025-02-10T05:12:47.505486Z', 'count': 2}, 'reason': 'TestCompleted', 'action': 'TestCompleted', 'note': 'Profile (default) with size (64) with rate (2mpps) for (120)s have completed', 'regarding': {'namespace': 'example-cnf', 'kind': 'TRexApp', 'name': 'trex-app', 'uid': '133af93f-5956-4451-84a2-93627533f0b1'}, 'reportingController': 'pod/job-trex-app-fcs5j', 'reportingInstance': 'trex-app'} +2025-02-10 05:12:47,549 - run-trex - INFO - { + "ibytes": 26160000109, + "ierrors": 0, + "ipackets": 240000001, + "obytes": 25200000105, + "oerrors": 0, + "opackets": 240000001, + "rx_bps": 1395717760.0, + "rx_bps_L1": 1651812700.0000002, + "rx_pps": 1600593.375, + "rx_util": 16.518127000000003, + "tx_bps": 1341922304.0, + "tx_bps_L1": 1597526544.0, + "tx_pps": 1597526.5, + "tx_util": 15.97526544 +} +2025-02-10 05:12:47,550 - run-trex - INFO - { + "ibytes": 26160000109, + "ierrors": 0, + "ipackets": 240000001, + "obytes": 25200000105, + "oerrors": 0, + "opackets": 240000001, + "rx_bps": 1384736640.0, + "rx_bps_L1": 1638816760.0, + "rx_pps": 1588000.75, + "rx_util": 16.3881676, + "tx_bps": 1336481024.0, + "tx_bps_L1": 1591048864.0, + "tx_pps": 1591049.0, + "tx_util": 15.91048864 +} +2025-02-10 05:12:47,550 - run-trex - INFO - +Packets lost from 0 to 1: 0 packets, which is 0.0000000000% packet loss +2025-02-10 05:12:47,550 - run-trex - INFO - Packets lost from 1 to 0: 0 packets, which is 0.0000000000% packet loss +2025-02-10 05:12:47,550 - run-trex - INFO - Total packets lost: 0 packets, which is 0.0000000000% packet loss +2025-02-10 05:12:47,565 - run-trex - INFO - CR to be utilized for event creation: {'apiVersion': 'events.k8s.io/v1', 'kind': 'Event', 'metadata': {'name': 'trex-app-j524nd', 'namespace': 'example-cnf', 'ownerReferences': [{'apiVersion': 'examplecnf.openshift.io/v1', 'kind': 'TRexApp', 'name': 'trex-app', 'uid': '133af93f-5956-4451-84a2-93627533f0b1', 'controller': True}]}, 'type': 'Normal', 'eventTime': '2025-02-10T05:12:47.505486Z', 'series': {'lastObservedTime': '2025-02-10T05:12:47.505486Z', 'count': 2}, 'reason': 'TestPassed', 'action': 'TestPassed', 'note': 'Test has passed with no packet loss, total packets: 480000002', 'regarding': {'namespace': 'example-cnf', 'kind': 'TRexApp', 'name': 'trex-app', 'uid': '133af93f-5956-4451-84a2-93627533f0b1'}, 'reportingController': 'pod/job-trex-app-fcs5j', 'reportingInstance': 'trex-app'} + +Test has passed :-) + +2025-02-10 05:12:47,587 - run-trex - DEBUG - +Disconnecting from server at 'trex-server':'4501' [SUCCESS] + +2025-02-10 05:12:47,614 - run-trex - DEBUG - Shutting down RPC client +``` + +From this output, you should check the following: + +- Confirm if the number of processed packets (`ipackets` and `opackets`) on each port is correct. In this scenario, we have around 240.000.000 packets. The TRex job lasted 120 seconds and it was injecting 2mpps (2.000.000 packets/s), so the number of packets processed per port corresponds to the parameters we've drafted. + - If having less packets than expected, it could be because of different reasons, for example: + - They've not been sent because packet rate was really high and, maybe, your system got saturated at some point, so that the real data rate was reduced. + - Timeout expired just at the moment where some packets were sent, Even though there's a time window to wait some more time for these packets, there could be some of them that are eventually lost. + - We could also have cases where we have more packets than expected, which will imply a negative packet loss (which is a passed case). This happens when TestPMD and/or TRex receive traffic that is not generated or consumed by these two entities, e.g. control packets generated by network devices in your setup that are reaching these pods and are increasing their counters. +- In both ports, if `ipackets` and `opackets` figure is the same (like in this case), this means that there's no packet loss, as it can be confirmed at the end of the logs entries (0.00% packet loss -> Test has passed). Same happens for negative packet loss. + - However, we will have packet loss if not receiving the same amount of packets that we're generating from TRex. + +These logs are generated by the Python script provided in the TRexApp component. The input it takes comes from TRex, and this information can be seen in `trexconfig` pod logs (it will print all the statistics checks made until now): + +``` +$ oc logs -n example-cnf trexconfig-5865745c74-qstk6 +... +-Per port stats table + ports | 0 | 1 + ----------------------------------------------------------------------------------------- + opackets | 240000001 | 240000001 + obytes | 25200000105 | 25200000105 + ipackets | 240000001 | 240000001 + ibytes | 26160000109 | 26160000109 + ierrors | 0 | 0 + oerrors | 0 | 0 + Tx Bw | 0.00 bps | 0.00 bps + +-Global stats enabled + Cpu Utilization : 0.0 % + Platform_factor : 1.0 + Total-Tx : 0.00 bps + Total-Rx : 0.00 bps + Total-PPS : 0.00 pps + Total-CPS : 0.00 cps + + Expected-PPS : 0.00 pps + Expected-CPS : 0.00 cps + Expected-BPS : 0.00 bps + + Active-flows : 0 Clients : 0 Socket-util : 0.0000 % + Open-flows : 0 Servers : 0 Socket : 0 Socket/Clients : -nan + drop-rate : 0.00 bps + current time : 32942.4 sec + test duration : 0.0 sec +``` + +You can see there that the `opackets` and `ipackets` figures correspond to what it's printed in `job-trex-app` pod. + +Finally, for `testpmd-app` pod, as said before, since this is a new copy of the pod, you will not be able to see the logs of the test that has been executed by the automation, but, if using DCI, you can retrieve these logs from the [Files section](https://www.distributed-ci.io/jobs/0ae26cc0-41b8-4f1b-86ce-1cbaf3a512b9/files) of the DCI job. + +From this source of information, you can find two main log files: + +- `example-cnf-pre-job-status.log`: it prints the status of all Example CNF components before starting the TRexApp job. +- `example-cnf-post-job-status.log`: it prints the status of all Example CNF components just after finishing the TRexApp job. + +So, in the second log file, you can find the logs of the `testpmd-app` pod that was used for the tests. Last entry is like this, and you can see that the figures managed by TestPMD correspond to what was generated on TRex, confirming that the job was in a good shape: + +``` +Port statistics ==================================== + ######################## NIC statistics for port 0 ######################## + RX-packets: 240000001 RX-missed: 0 RX-bytes: 24240000101 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 240000001 TX-errors: 0 TX-bytes: 24240000101 + Throughput (since last show) + Rx-pps: 0 Rx-bps: 0 + Tx-pps: 0 Tx-bps: 0 + ############################################################################ + + ######################## NIC statistics for port 1 ######################## + RX-packets: 240000001 RX-missed: 0 RX-bytes: 24240000101 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 240000001 TX-errors: 0 TX-bytes: 24240000101 + + Throughput (since last show) + Rx-pps: 0 Rx-bps: 0 + Tx-pps: 0 Tx-bps: 0 + ############################################################################ ``` ## Troubleshooting mode scenario -The baseline scenario is a good option to be able to launch Example CNF operators and deploy TRex automatically, being suitable for a CI system loop where the tests are executed N times and then we can extract conclusions from all the results obtained. However, we cannot really interact with either TestPMD or TRex. +The baseline scenario is a good option to be able to launch Example CNF operators and deploy TRex automatically, being suitable for a CI system loop where the tests are executed N times and then we can extract [conclusions](https://www.distributed-ci.io/analytics/keyvalues?query=%28tags+in+%5Bdaily%5D%29+and+%28%28status%3Dsuccess%29+and+%28name%3Dexample-cnf%29%29&range=last90Days&after=2024-11-12&before=2025-02-10&graphs=%255B%257B%2522keys%2522%253A%255B%257B%2522key%2522%253A%2522packet_loss_total_perc%2522%252C%2522color%2522%253A%2522%2523a3a3a3%2522%252C%2522axis%2522%253A%2522left%2522%257D%255D%252C%2522graphType%2522%253A%2522line%2522%257D%255D) from all the results obtained. However, we cannot really interact with either TestPMD or TRex. To achieve this goal, we can run Example CNF in troubleshooting mode by just providing some extra parameters to `dci-pipeline-schedule` call. In this way, all Example CNF operators will be created and all pods will keep up and running with all scripts prepared for being launched, but the automation will not take care of launching the test scripts and creating the TRex job, so that we can interact with both TestPMD and TRex to check on-line the behavior and results. @@ -158,26 +323,965 @@ You can launch this scenario with the following call to `dci-pipeline-schedule`: ``` $ export KUBECONFIG=/path/to/mycluster/kubeconfig -$ DCI_QUEUE_RESOURCE=mycluster dci-pipeline-schedule example-cnf +$ DCI_QUEUE_RESOURCE=mycluster dci-pipeline-schedule example-cnf example-cnf:ansible_extravars=ecd_run_deployment:0 +``` + +The key parameter is `ecd_run_deployment`; if set to 0, it will enable this troubleshooting scenario. + +Here's a [DCI job example](https://www.distributed-ci.io/jobs/0f05c4bc-2b40-40ae-a988-03a88c61d6b0/jobStates?sort=date) with this troubleshooting mode execution. + +### Check the pods + +We can check the pods that have been created after launching the pipeline: + +``` +$ oc get pods -n example-cnf +NAME READY STATUS RESTARTS AGE +cnf-app-mac-operator-controller-manager-74498bddcd-bdkjd 1/1 Running 0 5m22s +cnf-app-mac-operator-controller-manager-74498bddcd-xw96w 1/1 Running 0 5m22s +testpmd-app-b8f599d5f-hdhjt 1/1 Running 0 2m50s +testpmd-operator-controller-manager-6488b4c774-b6cv7 1/1 Running 0 4m8s +testpmd-operator-controller-manager-6488b4c774-g888r 1/1 Running 0 4m20s +trex-operator-controller-manager-6cdd46d4cd-9fntz 1/1 Running 0 3m16s +trex-operator-controller-manager-6cdd46d4cd-jzp42 1/1 Running 0 3m16s +trexconfig-589577d85-69m5x 1/1 Running 0 2m33s +``` + +We can see we have the same pods that in the baseline scenario excepting `job-trex-app`, which has not been created. In this scenario, this needs to be created manually once you want to start the traffic generation. + +### What is it executed on each data-plane pod? + +Basically, the scripts that are launched are the same than in the baseline scenario; however, since we're activating the troubleshooting mode, what's made by the entrypoint scripts of each pod is to generate the scripts that are eventually used, in the baseline scenario, to launch both TestPMD and TRex, but in this case, they're not launched in the automation. Instead of that, the pods go to sleep infinitely. + +So, with this, you can access to the pods and check that the scripts to be used during troubleshooting have been created: + +- `testpmd-app`: two scripts are created: `/usr/local/bin/example-cnf/run/testpmd-run` (same script that in the baseline scenario), and `/usr/local/bin/example-cnf/run/testpmd-interactive` (which launches `testpmd` in interactive mode instead of using auto-start mode). We would use `testpmd-interactive` for troubleshooting mode, since we can use TestPMD in interactive mode, and we can control the start/stop of this tool, the retrieval of statistics, etc. +- `trexconfig`: the script to be used is in `/usr/local/bin/example-cnf/trex-server-run` (same script that in the baseline scenario). + +### Start the traffic generation manually and check how it goes + +You have to follow these steps to be able to launch the same that you have seen in the baseline scenario. Good thing is that you will have the whole control of the process, so you can start, stop, retry, check, etc. whenever you want. + +You should need at least four terminal sessions to be able to interact with all resources fluently: 1) for TestPMD, 2) for TRexServer, 3) for printing live statistics from TRex using `tui`, and finally, 4) for launching TRexApp and check the logs of `job-trex-app`. + +You have to do the following: + +- In one session, start TestPMD in interactive mode: + +``` +# open a session in the testpmd-app pod +$ oc rsh -n example-cnf testpmd-app-b8f599d5f-hdhjt + +# check the testpmd-interactive script that has been generated by testpmd-wrapper +sh-4.4$ cat /usr/local/bin/example-cnf/run/testpmd-interactive +/usr/local/bin/example-cnf/testpmd -l 3,5,53 --in-memory -a 0000:86:02.7 -a 0000:86:03.6 --socket-mem 0,1024 -n 6 --proc-type auto --file-prefix pg -- --nb-cores=2 --rxq=1 --txq=1 --rxd=2048 --txd=2048 --i --eth-peer 0,20:04:0f:f1:89:01 --eth-peer 1,20:04:0f:f1:89:02 --forward-mode=mac + +# start testpmd in interactive mode (requires sudo) +sh-4.4$ sudo /usr/local/bin/example-cnf/run/testpmd-interactive +EAL: Detected CPU lcores: 96 +EAL: Detected NUMA nodes: 2 +EAL: Auto-detected process type: PRIMARY +EAL: Detected static linkage of DPDK +EAL: Selected IOVA mode 'VA' +EAL: 8000 hugepages of size 2097152 reserved, but no mounted hugetlbfs found for that size +EAL: VFIO support initialized +EAL: Using IOMMU type 1 (Type 1) +EAL: Probe PCI driver: net_iavf (8086:154c) device: 0000:86:02.7 (socket 1) +EAL: Probe PCI driver: net_iavf (8086:154c) device: 0000:86:03.6 (socket 1) +TELEMETRY: No legacy callbacks, legacy socket not created +Interactive-mode selected +Set mac packet forwarding mode +testpmd: create a new mbuf pool : n=163456, size=2176, socket=1 +testpmd: preferred mempool ops selected: ring_mp_mc +Configuring Port 0 (socket 1) +iavf_dev_init_vlan(): Failed to update vlan offload +iavf_dev_configure(): configure VLAN failed: -95 +iavf_set_rx_function(): request RXDID[1] in Queue[0] is legacy, set rx_pkt_burst as legacy for all queues + +Port 0: link state change event + +Port 0: link state change event +Port 0: 80:04:0F:F1:89:01 +Configuring Port 1 (socket 1) +iavf_dev_init_vlan(): Failed to update vlan offload +iavf_dev_configure(): configure VLAN failed: -95 +iavf_set_rx_function(): request RXDID[1] in Queue[0] is legacy, set rx_pkt_burst as legacy for all queues + +Port 1: link state change event + +Port 1: link state change event +Port 1: 80:04:0F:F1:89:02 +Checking link statuses... +Done +testpmd> + +# check stats (same counters we see in auto-start mode) - it doesn't mind if testpmd is not running yet, we can see the stats +testpmd> show port stats all + + ######################## NIC statistics for port 0 ######################## + RX-packets: 0 RX-missed: 0 RX-bytes: 0 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 0 TX-errors: 0 TX-bytes: 0 + + Throughput (since last show) + Rx-pps: 0 Rx-bps: 0 + Tx-pps: 0 Tx-bps: 0 + ############################################################################ + + ######################## NIC statistics for port 1 ######################## + RX-packets: 0 RX-missed: 0 RX-bytes: 0 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 0 TX-errors: 0 TX-bytes: 0 + + Throughput (since last show) + Rx-pps: 0 Rx-bps: 0 + Tx-pps: 0 Tx-bps: 0 + ############################################################################ + +# start testpmd +testpmd> start +mac packet forwarding - ports=2 - cores=2 - streams=2 - NUMA support enabled, MP allocation mode: native +Logical Core 5 (socket 1) forwards packets on 1 streams: + RX P=0/Q=0 (socket 1) -> TX P=1/Q=0 (socket 1) peer=20:04:0F:F1:89:02 +Logical Core 53 (socket 1) forwards packets on 1 streams: + RX P=1/Q=0 (socket 1) -> TX P=0/Q=0 (socket 1) peer=20:04:0F:F1:89:01 + + mac packet forwarding packets/burst=32 + nb forwarding cores=2 - nb forwarding ports=2 + port 0: RX queue number: 1 Tx queue number: 1 + Rx offloads=0x0 Tx offloads=0x10000 + RX queue: 0 + RX desc=2048 - RX free threshold=32 + RX threshold registers: pthresh=0 hthresh=0 wthresh=0 + RX Offloads=0x0 + TX queue: 0 + TX desc=2048 - TX free threshold=32 + TX threshold registers: pthresh=0 hthresh=0 wthresh=0 + TX offloads=0x10000 - TX RS bit threshold=32 + port 1: RX queue number: 1 Tx queue number: 1 + Rx offloads=0x0 Tx offloads=0x10000 + RX queue: 0 + RX desc=2048 - RX free threshold=32 + RX threshold registers: pthresh=0 hthresh=0 wthresh=0 + RX Offloads=0x0 + TX queue: 0 + TX desc=2048 - TX free threshold=32 + TX threshold registers: pthresh=0 hthresh=0 wthresh=0 + TX offloads=0x10000 - TX RS bit threshold=32 + +# you can reset statistics +testpmd> clear port stats all + + NIC statistics for port 0 cleared + + NIC statistics for port 1 cleared + +# after this, if you check statistics again, you can see they have been resetted +testpmd> show port stats all + + ######################## NIC statistics for port 0 ######################## + RX-packets: 0 RX-missed: 0 RX-bytes: 0 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 0 TX-errors: 0 TX-bytes: 0 + + Throughput (since last show) + Rx-pps: 0 Rx-bps: 0 + Tx-pps: 0 Tx-bps: 0 + ############################################################################ + + ######################## NIC statistics for port 1 ######################## + RX-packets: 0 RX-missed: 0 RX-bytes: 0 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 0 TX-errors: 0 TX-bytes: 0 + + Throughput (since last show) + Rx-pps: 0 Rx-bps: 0 + Tx-pps: 0 Tx-bps: 0 + ############################################################################ + +# stop testpmd and print final statistics +testpmd> stop +Telling cores to stop... +Waiting for lcores to finish... + + ---------------------- Forward statistics for port 0 ---------------------- + RX-packets: 0 RX-dropped: 0 RX-total: 0 + TX-packets: 0 TX-dropped: 0 TX-total: 0 + ---------------------------------------------------------------------------- + + ---------------------- Forward statistics for port 1 ---------------------- + RX-packets: 0 RX-dropped: 0 RX-total: 0 + TX-packets: 0 TX-dropped: 0 TX-total: 0 + ---------------------------------------------------------------------------- + + +++++++++++++++ Accumulated forward statistics for all ports+++++++++++++++ + RX-packets: 0 RX-dropped: 0 RX-total: 0 + TX-packets: 0 TX-dropped: 0 TX-total: 0 + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Done. + +# exit interactive mode +testpmd> quit + +Stopping port 0... +Stopping ports... +Done + +Stopping port 1... +Stopping ports... +Done + +Shutting down port 0... +Closing ports... +Port 0 is closed +Done + +Shutting down port 1... +Closing ports... +Port 1 is closed +Done + +Bye... + +# let's start again and leave it running +sh-4.4$ sudo /usr/local/bin/example-cnf/run/testpmd-interactive +# (interactive mode is started) +testpmd> start +# (testpmd is started) +``` + +- Configure TRex. + +``` +# open a session in the trexconfig pod +$ oc rsh -n example-cnf trexconfig-589577d85-69m5x + +# check the TRex config file to use, that was generated by trex-wrapper script: +sh-4.4$ cat /usr/local/bin/example-cnf/trex_cfg.yaml +- c: 4 + interfaces: + - '86:02.2' + - '86:03.7' + platform: + dual_if: + - socket: 1 + threads: + - 7 + - 51 + - 53 + - 55 + latency_thread_id: 5 + master_thread_id: 3 + port_info: + - dest_mac: 80:04:0f:f1:89:01 + src_mac: 20:04:0f:f1:89:01 + - dest_mac: 80:04:0f:f1:89:02 + src_mac: 20:04:0f:f1:89:02 + version: 2 + +# check trex-server-run script. Argument (4) means the number of cores used by TRex +sh-4.4$ cat /usr/local/bin/example-cnf/trex-server-run +/usr/local/bin/trex-server 4 + +# launch TRexServer, this calls _t-rex-64 binary in interactive mode (it uses -i argument) +sh-4.4$ sudo -E /usr/local/bin/example-cnf/trex-server-run + +# trex execution starts and statistics are displayed +-Per port stats table + ports | 0 | 1 + ----------------------------------------------------------------------------------------- + opackets | 0 | 0 + obytes | 0 | 0 + ipackets | 0 | 0 + ibytes | 0 | 0 + ierrors | 0 | 0 + oerrors | 0 | 0 + Tx Bw | 0.00 bps | 0.00 bps + +-Global stats enabled + Cpu Utilization : 0.0 % + Platform_factor : 1.0 + Total-Tx : 0.00 bps + Total-Rx : 0.00 bps + Total-PPS : 0.00 pps + Total-CPS : 0.00 cps + + Expected-PPS : 0.00 pps + Expected-CPS : 0.00 cps + Expected-BPS : 0.00 bps + + Active-flows : 0 Clients : 0 Socket-util : 0.0000 % + Open-flows : 0 Servers : 0 Socket : 0 Socket/Clients : -nan + drop-rate : 0.00 bps + current time : 2.0 sec + test duration : 0.0 sec + +# this can be closed with Ctrl-C (several times) +# if running again trex-server-run, counters are restarted +``` + +- Be able to launch the trex-console to check statistics in interactive mode. + +``` +# open another session in the trexconfig pod +$ oc rsh -n example-cnf trexconfig-589577d85-69m5x + +# let's launch trex-console +sh-4.4$ cd /opt/trex/trex-core/scripts +sh-4.4$ ./trex-console + +Using 'python3' as Python interpeter + + +Connecting to RPC server on localhost:4501 [SUCCESS] + + +Connecting to publisher server on localhost:4500 [SUCCESS] + + +Acquiring ports [0, 1]: [SUCCESS] + + +Server Info: + +Server version: v2.85 @ STL +Server mode: Stateless +Server CPU: 4 x Intel(R) Xeon(R) Gold 6248R CPU @ 3.00GHz +Ports count: 2 x 10.0Gbps @ Unknown + +-=TRex Console v3.0=- + +Type 'help' or '?' for supported actions + +trex> + +# verify port status +trex>portattr +Port Status + + port | 0 | 1 +----------------+----------------------+--------------------- +driver | net_i40e_vf | net_i40e_vf +description | Unknown | Unknown +link status | UP | UP +link speed | 10 Gb/s | 10 Gb/s +port status | IDLE | IDLE +promiscuous | off | off +multicast | off | off +flow ctrl | N/A | N/A +vxlan fs | - | - +-- | | +layer mode | Ethernet | Ethernet +src IPv4 | - | - +IPv6 | off | off +src MAC | 20:04:0f:f1:89:01 | 20:04:0f:f1:89:02 +--- | | +Destination | 80:04:0f:f1:89:01 | 80:04:0f:f1:89:02 +ARP Resolution | - | - +---- | | +VLAN | - | - +----- | | +PCI Address | 0000:86:02.2 | 0000:86:03.7 +NUMA Node | 1 | 1 +RX Filter Mode | hardware match | hardware match +RX Queueing | off | off +Grat ARP | off | off +------ | | + +# if we execute tui command, we can display live statistics + +trex> tui + +# statistics are displayed and a tui prompt appears so that new commands can be introduced + +tui> ``` -Here's a [DCI job example](https://www.distributed-ci.io/jobs/67fec9f4-8629-4ca9-8c8f-54ce2e7e85db/jobStates?sort=date) with this troubleshooting mode execution. +- Send traffic with TRex using the trex-console command (following [this](https://trex-tgn.cisco.com/trex/doc/trex_console.html#_tutorial)), to confirm the scenario is correctly configured. -### Check pods +``` +# in the trex prompt we have below tui statistics, start launching traffic +# try with UDP packets, 64B size, launching 12mpps during 100 seconds +trex>start -f stl/udp_1pkt_1mac.py -d 100 -m 12mpps + +Removing all streams from port(s) [0._, 1._]: [SUCCESS] + + +Attaching 1 streams to port(s) [0._]: [SUCCESS] + + +Attaching 1 streams to port(s) [1._]: [SUCCESS] + + +Starting traffic on port(s) [0._, 1._]: [SUCCESS] + +50.02 [ms] + +# while this is running, check testpmd and trex-server statistics, +# in this case, we can se packet loss (not all packets have been sent) +# because we are exceeding the capacity of the link (10 Mbps), we are reaching +# 99% CPU capacity on TRex pod +``` -TBD - https://docs.google.com/document/d/1H2ckIk1OaCFcEdjxFin5QcYf-qpmvEqwJvUUZt4sWIc/edit?tab=t.0#heading=h.63hal0xqwm0t +- Try now with a TRexApp job + +``` +# in a new terminal with access to the cluster, let's try with something easy +# send 1 packet per second during 10 seconds (so we should only see 10 packets) +$ cat trexapp.yml +apiVersion: examplecnf.openshift.io/v1 +kind: TRexApp +metadata: + namespace: example-cnf + name: trex-app + annotations: + "ansible.sdk.operatorframework.io/verbosity": "4" + "ansible.sdk.operatorframework.io/reconcile-period": "1m" +spec: + # TRex parameters + packetRate: 1pps + duration: 10 + packetSize: 64 + + # this needs to match with a RuntimeClass already created in the cluster, if present + runtime_class_name: performance-blueprint-profile + +$ oc apply -f trexapp.yml + +# then, a trex-app-job pod should be created and move to Running status: +$ oc get pods -n example-cnf +NAME READY STATUS RESTARTS AGE +cnf-app-mac-operator-controller-manager-74498bddcd-bdkjd 1/1 Running 0 67m +cnf-app-mac-operator-controller-manager-74498bddcd-xw96w 1/1 Running 0 67m +job-trex-app-4jkn5 1/1 Running 0 5s +testpmd-app-b8f599d5f-hdhjt 1/1 Running 0 64m +testpmd-operator-controller-manager-6488b4c774-b6cv7 1/1 Running 0 66m +testpmd-operator-controller-manager-6488b4c774-g888r 1/1 Running 0 66m +trex-operator-controller-manager-6cdd46d4cd-9fntz 1/1 Running 0 65m +trex-operator-controller-manager-6cdd46d4cd-jzp42 1/1 Running 0 65m +trexconfig-589577d85-69m5x 1/1 Running 0 64m + + +# wait 10s, we're sending 1 packet per second, so we should only see 10 packets in the trex and testpmd counters. +# eg. from testpmd stats output: + +testpmd> show port stats all + + ######################## NIC statistics for port 0 ######################## + RX-packets: 10 RX-missed: 0 RX-bytes: 1010 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 10 TX-errors: 0 TX-bytes: 1010 + + Throughput (since last show) + Rx-pps: 0 Rx-bps: 16 + Tx-pps: 0 Tx-bps: 16 + ############################################################################ + + ######################## NIC statistics for port 1 ######################## + RX-packets: 10 RX-missed: 0 RX-bytes: 1010 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 10 TX-errors: 0 TX-bytes: 1010 + + Throughput (since last show) + Rx-pps: 0 Rx-bps: 16 + Tx-pps: 0 Tx-bps: 16 + ############################################################################ + +# if checking job-trex-app logs, at the end, you should see that the execution was correct + +$ oc logs -n example-cnf job-trex-app-4jkn5 +... +2025-02-10 15:48:03,093 - run-trex - INFO - { + "ibytes": 1090, + "ierrors": 0, + "ipackets": 10, + "obytes": 1050, + "oerrors": 0, + "opackets": 10, + "rx_bps": 851.1156616210938, + "rx_bps_L1": 1007.2836647033693, + "rx_pps": 0.9760500192642212, + "rx_util": 1.0072836647033692e-05, + "tx_bps": 819.8820190429688, + "tx_bps_L1": 976.0500221252441, + "tx_pps": 0.9760500192642212, + "tx_util": 9.760500221252442e-06 +} +2025-02-10 15:48:03,093 - run-trex - INFO - { + "ibytes": 1090, + "ierrors": 0, + "ipackets": 10, + "obytes": 1050, + "oerrors": 0, + "opackets": 10, + "rx_bps": 851.1156616210938, + "rx_bps_L1": 1007.2836647033693, + "rx_pps": 0.9760500192642212, + "rx_util": 1.0072836647033692e-05, + "tx_bps": 819.8820190429688, + "tx_bps_L1": 976.0500221252441, + "tx_pps": 0.9760500192642212, + "tx_util": 9.760500221252442e-06 +} +2025-02-10 15:48:03,094 - run-trex - INFO - +Packets lost from 0 to 1: 0 packets, which is 0.0000000000% packet loss +2025-02-10 15:48:03,094 - run-trex - INFO - Packets lost from 1 to 0: 0 packets, which is 0.0000000000% packet loss +2025-02-10 15:48:03,094 - run-trex - INFO - Total packets lost: 0 packets, which is 0.0000000000% packet loss +2025-02-10 15:48:03,108 - run-trex - INFO - CR to be utilized for event creation: {'apiVersion': 'events.k8s.io/v1', 'kind': 'Event', 'metadata': {'name': 'trex-app-q3sia4', 'namespace': 'example-cnf', 'ownerReferences': [{'apiVersion': 'examplecnf.openshift.io/v1', 'kind': 'TRexApp', 'name': 'trex-app', 'uid': 'b790b8f3-d674-488f-a8b4-af72840ff752', 'controller': True}]}, 'type': 'Normal', 'eventTime': '2025-02-10T15:48:03.053732Z', 'series': {'lastObservedTime': '2025-02-10T15:48:03.053732Z', 'count': 2}, 'reason': 'TestPassed', 'action': 'TestPassed', 'note': 'Test has passed with no packet loss, total packets: 20', 'regarding': {'namespace': 'example-cnf', 'kind': 'TRexApp', 'name': 'trex-app', 'uid': 'b790b8f3-d674-488f-a8b4-af72840ff752'}, 'reportingController': 'pod/job-trex-app-4jkn5', 'reportingInstance': 'trex-app'} + +Test has passed :-) +``` + +- Remove the TRexApp job once finished, so that this can be recreated. + +``` +$ oc delete trexapp trex-app +trexapp.examplecnf.openshift.io "trex-app" deleted +``` + +- Also, close the TestPMD execution (quit command) and TRex execution with Ctrl-C, so that the statistics are restarted for the next run. ## Draining scenario +We can use the troubleshooting mode to validate some interesting use cases, such as analyzing the impact of a node draining while TestPMD and TRex are exchanging traffic. This scenario is useful to understand how this workload would behave during cluster upgrades, where cluster nodes are cordoned and drained, thus ensuring fault tolerance in the workflow while nodes get reconciliation. + ### Manual testing -TBD - https://docs.google.com/document/d/1DDZubnc16FCLPb8xNF2ybWhVbU3q366KmkITa2q1cFQ/edit?tab=t.0#heading=h.63hal0xqwm0t +To test this scenario, we use the troubleshooting scenario as base, and then we perform different actions on the deployed resources to force a node draining. [Here](https://www.youtube.com/watch?v=ba1yOKUPlIc&t=3s) you have a live demonstration of this scenario. + +- Deploy the [troubleshooting mode](#troubleshooting-mode-scenario) scenario. Let's check the pods that are deployed, also printing the worker node where each pod is located: + +``` +# in this case, TestPMD is running in worker-2 and TRex is running in worker-0 +$ oc get pods -o wide +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +cnf-app-mac-operator-controller-manager-6f55449fcf-ngtm5 1/1 Running 0 3h4m 10.129.3.8 worker-1 +cnf-app-mac-operator-controller-manager-6f55449fcf-wqvzk 1/1 Running 0 3h3m 10.130.2.59 worker-3 +testpmd-app-846496dbd9-zp9wn 1/1 Running 0 3h 10.128.2.54 worker-2 +testpmd-operator-controller-manager-587876bb54-67pjh 1/1 Running 0 3h2m 10.129.3.10 worker-1 +testpmd-operator-controller-manager-587876bb54-9btq2 1/1 Running 0 3h2m 10.130.2.61 worker-3 +trex-operator-controller-manager-7b698f98cb-b5zvk 1/1 Running 0 3h 10.130.2.63 worker-3 +trex-operator-controller-manager-7b698f98cb-j6rq7 1/1 Running 0 3h1m 10.129.3.12 worker-1 +trexconfig-995599757-2q7x6 1/1 Running 0 179m 10.131.0.48 worker-0 +``` + +- Make sure TestPMD and TRex are running in `testpmd-app` and `trexconfig` pods. You can also have a terminal with `tui` running on TRex to retrieve live statistics. + +- Launch a TRex test with enough duration to perform node cording-draining + +``` +# let's leave enough time for TRex job to perform the node cordon-draining process manually +$ cat trexapp.yml +apiVersion: examplecnf.openshift.io/v1 +kind: TRexApp +metadata: + namespace: example-cnf + name: trex-app + annotations: + "ansible.sdk.operatorframework.io/verbosity": "4" + "ansible.sdk.operatorframework.io/reconcile-period": "1m" +spec: + # TRex parameters + packetRate: 10kpps + duration: 300 + packetSize: 64 + + # this needs to match with a RuntimeClass already created in the cluster, if present + runtime_class_name: performance-blueprint-profile + +$ oc apply -f trexapp.yml + +# then, a trex-app-job pod should be created and move to Running status: +$ oc get pods -n example-cnf +NAME READY STATUS RESTARTS AGE +cnf-app-mac-operator-controller-manager-6f55449fcf-ngtm5 1/1 Running 0 3h25m +cnf-app-mac-operator-controller-manager-6f55449fcf-wqvzk 1/1 Running 0 3h24m +job-trex-app-wfd6f 0/1 Running 0 22s +testpmd-app-846496dbd9-zp9wn 1/1 Running 0 3h20m +testpmd-operator-controller-manager-587876bb54-67pjh 1/1 Running 0 3h22m +testpmd-operator-controller-manager-587876bb54-9btq2 1/1 Running 0 3h22m +trex-operator-controller-manager-7b698f98cb-b5zvk 1/1 Running 0 3h21m +trex-operator-controller-manager-7b698f98cb-j6rq7 1/1 Running 0 3h21m +trexconfig-995599757-2q7x6 1/1 Running 0 3h20m + +# up to this moment, wait until receiving traffic in trex-server to confirm the job is working +``` + +- Cordon-drain the node where TestPMD is running + +``` +# cordon the node (in this case, it is worker-2) +$ oc adm cordon worker-2 +node/worker-2 cordoned + +# wait until it moves to SchedulingDisabled +$ oc get nodes +NAME STATUS ROLES AGE VERSION +master-0 Ready control-plane,master 46h v1.27.16+03a907c +master-1 Ready control-plane,master 46h v1.27.16+03a907c +master-2 Ready control-plane,master 46h v1.27.16+03a907c +worker-0 Ready worker 45h v1.27.16+03a907c +worker-1 Ready worker 45h v1.27.16+03a907c +worker-2 Ready,SchedulingDisabled worker 45h v1.27.16+03a907c +worker-3 Ready worker 45h v1.27.16+03a907c + +# drain the node, removing testpmd pod +$ oc adm drain worker-2 --pod-selector example-cnf-type=cnf-app --delete-emptydir-data +node/worker-2 already cordoned +evicting pod example-cnf/testpmd-app-846496dbd9-zp9wn +pod/testpmd-app-846496dbd9-zp9wn evicted +node/worker-2 drained + +# testpmd pod is removed and you will lose access to this; then, packet loss will start to appear +## check trex-server statistics to see that; in trexserver, you will see counter increases in +# opackets but not in ipackets +``` + +- Meantime, a new `testpmd-app` will appear, but again, scripts will be created and the pod will keep sleeping infinitely. Let's relaunch `testpmd` on the new `testpmd-app` pod. + +``` +# check pods, testpmd pod should be recreated in a different pod - in fact, it is recreated at the +# same time the first pod is deleted, but here we will wait until it is removed to really confirm +# we have packet loss +# find the new testpmd pod name and confirm it is allocated in a different worker node +## now we have it on worker-1 +$ oc get pods -o wide +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +cnf-app-mac-operator-controller-manager-6f55449fcf-ngtm5 1/1 Running 0 3h32m 10.129.3.8 worker-1 +cnf-app-mac-operator-controller-manager-6f55449fcf-wqvzk 1/1 Running 0 3h31m 10.130.2.59 worker-3 +job-trex-app-wfd6f 0/1 Running 0 7m26s 10.130.2.67 worker-3 +testpmd-app-846496dbd9-zslp7 1/1 Running 0 6m38s 10.129.3.32 worker-1 +testpmd-operator-controller-manager-587876bb54-67pjh 1/1 Running 0 3h29m 10.129.3.10 worker-1 +testpmd-operator-controller-manager-587876bb54-9btq2 1/1 Running 0 3h29m 10.130.2.61 worker-3 +trex-operator-controller-manager-7b698f98cb-b5zvk 1/1 Running 0 3h28m 10.130.2.63 worker-3 +trex-operator-controller-manager-7b698f98cb-j6rq7 1/1 Running 0 3h28m 10.129.3.12 worker-1 +trexconfig-995599757-2q7x6 1/1 Running 0 3h27m 10.131.0.48 worker-0 + +# open a session in the testpmd-app pod +$ oc rsh -n example-cnf testpmd-app-846496dbd9-zslp7 + +# start testpmd in interactive mode (requires sudo) +sh-4.4$ sudo /usr/local/bin/example-cnf/run/testpmd-interactive + +# start testpmd +testpmd> start +``` + +- Then, start checking statistics again, there should not be packet loss in this moment until the end. + +``` +# check again statistics in both sides, wait until the end of the execution to see the final results +## testpmd - counter should start increasing, the stats are restarted because it is a new pod +testpmd> show port stats all + + ######################## NIC statistics for port 0 ######################## + RX-packets: 555585 RX-missed: 0 RX-bytes: 56113880 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 555675 TX-errors: 0 TX-bytes: 56122990 + + Throughput (since last show) + Rx-pps: 7976 Rx-bps: 6444920 + Tx-pps: 7977 Tx-bps: 6446080 + ############################################################################ + + ######################## NIC statistics for port 1 ######################## + RX-packets: 555675 RX-missed: 0 RX-bytes: 56122970 + RX-errors: 0 + RX-nombuf: 0 + TX-packets: 555585 TX-errors: 0 TX-bytes: 56113900 + + Throughput (since last show) + Rx-pps: 7977 Rx-bps: 6445848 + Tx-pps: 7976 Tx-bps: 6444688 + ############################################################################ + +## trex-server - ipackets starts to increase again + +-Per port stats table + ports | 0 | 1 + ----------------------------------------------------------------------------------------- + opackets | 1200000 | 1200000 + obytes | 126000000 | 126000000 + ipackets | 945114 | 945080 + ibytes | 103016761 | 103013133 + ierrors | 0 | 0 + oerrors | 0 | 0 + Tx Bw | 251.18 Kbps | 251.32 Kbps + +-Global stats enabled + Cpu Utilization : 0.1 % + Platform_factor : 1.0 + Total-Tx : 502.50 Kbps + Total-Rx : 521.64 Kbps + Total-PPS : 598.21 pps + Total-CPS : 0.00 cps + + Expected-PPS : 0.00 pps + Expected-CPS : 0.00 cps + Expected-BPS : 0.00 bps + + Active-flows : 0 Clients : 0 Socket-util : 0.0000 % + Open-flows : 0 Servers : 0 Socket : 0 Socket/Clients : -nan + drop-rate : 0.00 bps + current time : 152.8 sec + test duration : 0.0 sec + + +# to conclude, stop testpmd - you will see the number of packets sent-received are the same +testpmd> stop + +Telling cores to stop... +Waiting for lcores to finish... + + ---------------------- Forward statistics for port 0 ---------------------- + RX-packets: 555586 RX-dropped: 0 RX-total: 555586 + TX-packets: 555676 TX-dropped: 0 TX-total: 555676 + ---------------------------------------------------------------------------- + + ---------------------- Forward statistics for port 1 ---------------------- + RX-packets: 555676 RX-dropped: 0 RX-total: 555676 + TX-packets: 555586 TX-dropped: 0 TX-total: 555586 + ---------------------------------------------------------------------------- + + +++++++++++++++ Accumulated forward statistics for all ports+++++++++++++++ + RX-packets: 1111262 RX-dropped: 0 RX-total: 1111262 + TX-packets: 1111262 TX-dropped: 0 TX-total: 1111262 + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +# if checking job-trex-app logs, at the end, you should see that the execution failed because there were packet loss + +$ oc logs job-trex-app-wfd6f + +2024-09-13 20:23:13,913 - run-trex - INFO - +Packets lost from 0 to 1: 254920 packets, which is 21.243333333333332% packet loss +2024-09-13 20:23:13,914 - run-trex - INFO - Packets lost from 1 to 0: 254887 packets, which is 21.240583333333333% packet loss +2024-09-13 20:23:13,914 - run-trex - INFO - Total packets lost: 509807 packets, which is 21.241958333333333% packet loss +2024-09-13 20:23:13,921 - run-trex - INFO - CR to be utilized for event creation: {'apiVersion': 'events.k8s.io/v1', 'kind': 'Event', 'metadata': {'name': 'trex-app-qm4rgv', 'namespace': 'example-cnf', 'ownerReferences': [{'apiVersion': 'examplecnf.openshift.io/v1', 'kind': 'TRexApp', 'name': 'trex-app', 'uid': '5c0ac18f-03ab-4f7b-8847-19628355a459', 'controller': True}]}, 'type': 'Normal', 'eventTime': '2024-09-13T20:23:13.892938Z', 'series': {'lastObservedTime': '2024-09-13T20:23:13.892938Z', 'count': 2}, 'reason': 'TestFailed', 'action': 'TestFailed', 'note': 'Test has failed with 509807 packets lost, resulting in 21.241958333333333% packet loss', 'regarding': {'namespace': 'example-cnf', 'kind': 'TRexApp', 'name': 'trex-app', 'uid': '5c0ac18f-03ab-4f7b-8847-19628355a459'}, 'reportingController': 'pod/job-trex-app-l9qlt', 'reportingInstance': 'trex-app'} +2024-09-13 20:23:13,934 - run-trex - DEBUG - +Disconnecting from server at 'trex-server':'4501' [SUCCESS] +``` + +- Remove the TRexApp job once finished, so that this can be recreated. + +``` +$ oc delete trexapp trex-app +trexapp.examplecnf.openshift.io "trex-app" deleted +``` + +- Also, close the TestPMD execution (quit command) and TRex execution with Ctrl-C, so that the statistics are restarted for the next run. + +- Also, uncordon the cordoned node + +``` +$ oc adm uncordon worker-2 +node/worker-2 uncordoned +``` ### Automation +This scenario can be automated with a couple of pipelines, each of them invoking a different hook that performs the steps we have presented before: + +- With this pipeline, we will launch [this hook](https://github.com/dci-labs/example-cnf-config/tree/master/launch_trex_job) to create a new TRexApp that will keep running in continuous mode, so that, in a new job, we will retrieve the logs from this execution after making a node cordon-draining: + +``` +$ cat example-cnf-extra-trex-job-pipeline.yml +--- +- name: example-cnf-extra-trex-job + stage: cnf-extra-deployment + # Using job name for prev_stages + prev_stages: [example-cnf] + ansible_cfg: /usr/share/dci-openshift-agent/ansible.cfg + ansible_playbook: /usr/share/dci-openshift-app-agent/dci-openshift-app-agent.yml + ansible_inventory: /etc/dci-openshift-app-agent/hosts.yml + configuration: "myqueue" + dci_credentials: ~/.config/dci-pipeline/credentials.yml + ansible_extravars: + dci_cache_dir: /var/lib/dci-pipeline + dci_tags: + - debug + + # Including example-cnf hooks + dci_config_dir: /usr/share/example-cnf-config/launch_trex_job + dci_gits_to_components: + - /usr/share/example-cnf-config + + # Do not delete resources when the job finishes + dci_teardown_on_success: false + dci_teardown_on_failure: false + + # Do not run workload API check to save some time + check_workload_api: false + + # We want TRexApp job to run in continuous mode but with a limited duration, leaving + # enough time to perform a draining process afterwards + ecd_trex_duration: 900 + ecd_trex_continuous_mode: true + # Name for the new TRexApp job + ecd_trex_app_new_cr_name: trex-app-new + + use_previous_topic: true + components: + - nfv-example-cnf-index + inputs: + kubeconfig: kubeconfig_path +``` + +- After this, with this another pipeline, we will launch [this hook](https://github.com/dci-labs/example-cnf-config/tree/master/draining_validation) to perform the steps to emulate the cluster upgrade process; we'll cordon and drain the node where TestPMD is running, and then wait for TestPMD to be relocated in a different worker node, so that the test can continue without packet loss (but of course, during the whole duration of the TRexApp job, we will have packet loss). + +``` +$ cat example-cnf-draining-pipeline.yml +--- +- name: example-cnf-draining + stage: cnf-validation + # Using job name for prev_stages + prev_stages: [example-cnf-extra-trex-job] + ansible_cfg: /usr/share/dci-openshift-agent/ansible.cfg + ansible_playbook: /usr/share/dci-openshift-app-agent/dci-openshift-app-agent.yml + ansible_inventory: /etc/dci-openshift-app-agent/hosts.yml + configuration: "myqueue" + dci_credentials: ~/.config/dci-pipeline/credentials.yml + ansible_extravars: + dci_cache_dir: /var/lib/dci-pipeline + dci_tags: + - debug + + # Including example-cnf hooks + dci_config_dir: /usr/share/example-cnf-config/draining_validation + dci_gits_to_components: + - /usr/share/example-cnf-config + + # Do not delete resources when the job finishes + dci_teardown_on_success: false + dci_teardown_on_failure: false + + # Do not run workload API check to save some time + check_workload_api: false + + # Name for the TRexApp job to check + ecd_trex_app_cr_name_to_check: trex-app-new + + use_previous_topic: true + components: + - nfv-example-cnf-index + inputs: + kubeconfig: kubeconfig_path +``` + +This can be called with the following `dci-pipeline` command: + +``` +$ export KUBECONFIG=/path/to/mycluster/kubeconfig +$ DCI_QUEUE_RESOURCE=mycluster dci-pipeline-schedule example-cnf example-cnf-extra-trex-job example-cnf-draining +``` + +Here we have a [pipeline execution example from DCI](https://www.distributed-ci.io/jobs?limit=20&offset=0&sort=-created_at&where=pipeline_id:431fac99-69e5-4073-acc9-f4299d275bed,state:active) with the concatenation of these jobs at the end of the pipeline chain. + ## Test Example CNF during upgrades -## Create a new TRexApp job +Another scenario that can be validated is to really test Example CNF during a cluster upgrade. We can use the following pipelines for that: + +- This pipeline creates Example CNF on a cluster, and after finishing the baseline scenario, it creates a new TRexApp job with a given profile, where we leave enough duration to check, later on, what has been the result of the test, once upgrade finishes. + +``` +$ cat example-cnf-continuous-pipeline.yml +--- +- name: example-cnf + stage: workload + prev_stages: [openshift-upgrade, openshift] + ansible_cfg: /usr/share/dci-openshift-agent/ansible.cfg + ansible_playbook: /usr/share/dci-openshift-app-agent/dci-openshift-app-agent.yml + ansible_inventory: /etc/dci-openshift-app-agent/hosts.yml + configuration: "myqueue" + dci_credentials: ~/.config/dci-pipeline/credentials.yml + ansible_extravars: + dci_cache_dir: /var/lib/dci-pipeline + dci_tags: + - debug + + # Including example-cnf hooks + dci_config_dir: /usr/share/example-cnf-config/testpmd + dci_gits_to_components: + - /usr/share/example-cnf-config + + # Do not delete resources when the job finishes + dci_teardown_on_success: false + dci_teardown_on_failure: false + + # Point to SRIOV config + example_cnf_sriov_file: /usr/share/mycluster-sriov-config.yml + + # Tune example-cnf execution + ## Allow testpmd in reduced mode + ecd_testpmd_reduced_mode: 1 + ## Tune TRexApp parameters + ecd_trex_duration: 120 + ecd_trex_packet_rate: 2mpps + ecd_trex_packet_size: 64 + + # Allow failures in TRex jobs in case we have packet loss because of the data rate we're generating + example_cnf_skip_trex_job_failure: true + + # To add an extra TRex profile, define the following ecd_trex_test_config + ecd_trex_test_config: + - name: pkt-64-10kpps-6600s + packet_size: 64 + packet_rate: 10kpps + duration: 6600 + # Wait the end of the TRex profile + ecd_trex_tests_wait: false + + use_previous_topic: true + components: + - nfv-example-cnf-index + inputs: + kubeconfig: kubeconfig_path +``` + +- Then, we have to upgrade the OCP cluster. + +- After achieving the cluster upgrade, we can run this another pipeline, launching [this hook](https://github.com/dci-labs/example-cnf-config/tree/master/upgrade_validation) to validate Example CNF after the upgrade: + +``` +$ cat example-cnf-validation-pipeline.yml +--- +- name: example-cnf-validation + stage: cnf-validation + prev_stages: [ocp-upgrade] + ansible_cfg: /usr/share/dci-openshift-agent/ansible.cfg + ansible_playbook: /usr/share/dci-openshift-app-agent/dci-openshift-app-agent.yml + ansible_inventory: /etc/dci-openshift-app-agent/hosts.yml + configuration: "myqueue" + dci_credentials: ~/.config/dci-pipeline/credentials.yml + ansible_extravars: + dci_cache_dir: /var/lib/dci-pipeline + dci_tags: + - debug + + # Including example-cnf hooks + dci_config_dir: /usr/share/example-cnf-config/upgrade_validation + dci_gits_to_components: + - /usr/share/example-cnf-config + + # Do not delete resources when the job finishes + dci_teardown_on_success: false + dci_teardown_on_failure: false + + use_previous_topic: true + components: + - nfv-example-cnf-index + inputs: + kubeconfig: kubeconfig_path +``` + +As usual, you can use `dci-pipeline` to test this scenario, but this requires to run the upgrade as a mid step. Here's an [example on DCI](https://www.distributed-ci.io/jobs?limit=20&offset=0&sort=-created_at&where=pipeline_id:7fc428f4-e3fd-4c70-8323-19c96aa6da16,state:active) with this pipeline configuration. ## Remove Example CNF deployment @@ -187,7 +1291,9 @@ You can do it with the following call to `dci-pipeline-schedule`: ``` $ export KUBECONFIG=/path/to/mycluster/kubeconfig -$ DCI_QUEUE_RESOURCE=mycluster dci-pipeline-schedule example-cnf +$ DCI_QUEUE_RESOURCE=mycluster dci-pipeline-schedule example-cnf example-cnf:ansible_tags=kubeconfig,dci,job,success example-cnf:ansible_extravars=dci_teardown_on_success:true example-cnf:ansible_extravars=dci_teardown_on_failure:true example-cnf:ansible_extravars=ecd_cnf_namespace:example-cnf ``` -Here's a [DCI job example](https://www.distributed-ci.io/jobs/22a50cd0-6bc6-439c-94af-e401ca467962/jobStates?sort=date) with this cleanup execution. +The key to enable this behavior is just to call to `kubeconfig,dci,job` (these are always mandatory) and `success` stages from `dci-openshift-app-agent`, then always running teardown and providing the Example CNF namespace (since this is created in the automation, so for this case, it needs to be provided manually). + +Here's a [DCI job example](https://www.distributed-ci.io/jobs/6973c66e-e5db-4e22-8d0a-a6f5603b846c/jobStates?sort=date) with this cleanup execution.