Skip to content

cli_config: push config and detect changes when platform lacks diff support #338

cli_config: push config and detect changes when platform lacks diff support

cli_config: push config and detect changes when platform lacks diff support #338

Workflow file for this run

---
name: "Integration tests 💻"
"on":
pull_request_target:
branches: [main]
types:
- labeled
- opened
- reopened
- synchronize
paths:
- "plugins/**"
- "tests/integration/**"
workflow_dispatch:
inputs:
ansible_version:
description: "Ansible core version to test"
required: true
type: choice
options:
- "2.15"
- "2.16"
- "2.17"
- "2.18"
- "2.19"
- "2.20"
- "milestone"
- "devel"
default: "devel"
debug:
description: "Enable debug steps"
required: false
type: boolean
default: false
ssh_type:
description: "network_cli SSH transport (paramiko or libssh)"
required: false
type: choice
options:
- "libssh"
- "paramiko"
default: "libssh"
jobs:
lab-create:
uses: ansible/ansible-content-actions/.github/workflows/cml_lab_create.yaml@main
with:
topology_path: tests/integration/labs/multi.yaml
# lab_title_override: "Optional custom lab title"
secrets:
virl_host: ${{ secrets.VIRL_HOST }}
virl_username: ${{ secrets.VIRL_USERNAME }}
virl_password: ${{ secrets.VIRL_PASSWORD }}
integration-tests:
needs: lab-create
name: "${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ssh_type || 'libssh' }} & ansible-core ${{ matrix.ansible_version }}"
runs-on: ubuntu-latest
if: ${{ !github.event.pull_request || contains(github.event.pull_request.labels.*.name, 'safe to test') }}
env:
PY_COLORS: "1"
ANSIBLE_COLLECTIONS_PATHS: "/home/runner/.ansible/collections"
# workflow_dispatch: use chosen ssh_type; PR/schedule: default libssh
CLI_SSH_TYPE: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ssh_type || 'libssh' }}
strategy:
fail-fast: true
matrix: # There is no official support for matrix here as multiple applaince are needed per run, test against one core version.
ansible_version: ${{ github.event_name == 'workflow_dispatch' && fromJSON(format('["{0}"]', github.event.inputs.ansible_version)) || fromJSON('["devel"]') }}
steps:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ (contains(matrix.ansible_version, 'devel') || contains(matrix.ansible_version, 'milestone')) && '3.13' || '3.12' }}
- name: DEBUG Show pip list before installs
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug == 'true' || github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'debug') }}
run: |
python3 -m pip --version
python3 -m pip list | sort
- name: Upgrade pip and wheel
run: python3 -m pip install --upgrade pip wheel ansible-pylibssh paramiko genie passlib scp ncclient ntc_templates pyats jxmlease ssh-python
- name: DEBUG Show pip list after base deps install
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug == 'true' || github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'debug') }}
run: |
python3 -m pip list | sort
- name: Install ansible-core (${{ matrix.ansible_version }}) - Stable version
run: python3 -m pip install "ansible-core~=${{ matrix.ansible_version }}.0" --disable-pip-version-check
if: ${{ !contains(matrix.ansible_version, 'devel') && !contains(matrix.ansible_version, 'milestone') }}
- name: Checkout ansible-core (${{ matrix.ansible_version }}) - Branch
uses: actions/checkout@v4
with:
repository: ansible/ansible
ref: ${{ matrix.ansible_version }}
path: ansible-core-source
if: ${{ contains(matrix.ansible_version, 'devel') || contains(matrix.ansible_version, 'milestone') }}
- name: Install ansible-core (${{ matrix.ansible_version }}) - Branch
run: python3 -m pip install ./ansible-core-source --disable-pip-version-check
if: ${{ contains(matrix.ansible_version, 'devel') || contains(matrix.ansible_version, 'milestone') }}
- name: Create collections directory structure
run: |
mkdir -p /home/runner/.ansible/collections/ansible_collections/cisco
mkdir -p /home/runner/.ansible/collections/ansible_collections/ansible
- name: Clone cisco.nxos collection (main branch)
run: |
git clone --depth=1 --branch main https://github.com/ansible-collections/cisco.nxos.git /home/runner/.ansible/collections/ansible_collections/cisco/nxos
- name: Clone cisco.ios collection (main branch)
run: |
git clone --depth=1 --branch main https://github.com/ansible-collections/cisco.ios.git /home/runner/.ansible/collections/ansible_collections/cisco/ios
- name: Clone cisco.iosxr collection (main branch)
run: |
git clone --depth=1 --branch main https://github.com/ansible-collections/cisco.iosxr.git /home/runner/.ansible/collections/ansible_collections/cisco/iosxr
- name: Clone ansible.utils collection (main branch)
run: |
git clone --depth=1 --branch main https://github.com/ansible-collections/ansible.utils.git /home/runner/.ansible/collections/ansible_collections/ansible/utils
- name: Clone netcommon collection (PR branch or repo)
run: |
if [ -n "${{ github.event.pull_request.head.repo.full_name }}" ]; then
REPO_URL="${{ github.event.pull_request.head.repo.full_name }}"
BRANCH_REF="${{ github.event.pull_request.head.sha }}"
IS_SHA=true
else
REPO_URL="${{ github.repository }}"
BRANCH_REF="${{ github.ref_name }}"
IS_SHA=false
fi
echo "Cloning netcommon from git+https://github.com/${REPO_URL}.git, ref: ${BRANCH_REF}"
if [ "$IS_SHA" = "true" ]; then
# For SHA, clone with more depth to ensure we get the commit
git clone --depth=100 --no-single-branch https://github.com/${REPO_URL}.git /home/runner/.ansible/collections/ansible_collections/ansible/netcommon
cd /home/runner/.ansible/collections/ansible_collections/ansible/netcommon
git fetch origin ${BRANCH_REF} || git fetch --unshallow || true
git checkout ${BRANCH_REF}
else
# For branch name, use standard shallow clone
git clone --depth=1 --branch ${BRANCH_REF} https://github.com/${REPO_URL}.git /home/runner/.ansible/collections/ansible_collections/ansible/netcommon
fi
- name: Install Python dependencies from collections
run: |
if [ -f "/home/runner/.ansible/collections/ansible_collections/cisco/nxos/requirements.txt" ]; then
python3 -m pip install -r /home/runner/.ansible/collections/ansible_collections/cisco/nxos/requirements.txt
fi
if [ -f "/home/runner/.ansible/collections/ansible_collections/ansible/netcommon/requirements.txt" ]; then
python3 -m pip install -r /home/runner/.ansible/collections/ansible_collections/ansible/netcommon/requirements.txt
fi
- name: DEBUG Show pip list after ansible-core install
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug == 'true' || github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'debug') }}
run: |
python3 -m pip list | sort
- name: Read collection metadata from galaxy.yml
id: identify
uses: ansible-network/github_actions/.github/actions/identify_collection@main
with:
source_path: /home/runner/.ansible/collections/ansible_collections/ansible/netcommon
- name: DEBUG lab_nodes input
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug == 'true' || github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'debug') }}
shell: bash
env:
LAB_NODES: ${{ needs.lab-create.outputs.lab_nodes_json }}
run: |
echo 'LAB_NODES (raw):'
echo "$LAB_NODES"
echo
- name: Generate inventory from lab_nodes and template
id: render_inventory
shell: bash
working-directory: ${{ steps.identify.outputs.collection_path }}
env:
LAB_NODES_JSON: ${{ needs.lab-create.outputs.lab_nodes_json }}
RUNNER_TEMP: ${{ runner.temp }}
CLI_SSH_TYPE: ${{ env.CLI_SSH_TYPE }}
run: |
set -euo pipefail
if ! command -v jq >/dev/null 2>&1; then
sudo apt-get update -y >/dev/null 2>&1 || true
sudo apt-get install -y jq >/dev/null 2>&1 || true
fi
# Extract DHCP IPs for each node
nxos_ip=$(echo "$LAB_NODES_JSON" | jq -r '.nodes.nxos // empty')
iosxr_ip=$(echo "$LAB_NODES_JSON" | jq -r '.nodes.iosxr // empty')
iosxe_ip=$(echo "$LAB_NODES_JSON" | jq -r '.nodes.iosxe // empty')
ubuntu_ip=$(echo "$LAB_NODES_JSON" | jq -r '.nodes.ubuntu // empty')
if [ -z "$nxos_ip" ] || [ -z "$iosxr_ip" ] || [ -z "$iosxe_ip" ] || [ -z "$ubuntu_ip" ]; then
echo "Missing one or more required nodes (nxos, iosxr, iosxe, ubuntu) in LAB_NODES_JSON"
echo "Available keys:" $(echo "$LAB_NODES_JSON" | jq -r '.nodes | keys | join(", ")')
exit 1
fi
# Compute ports from last octet of each DHCP IP
nxos_last_octet="${nxos_ip##*.}"
nxos_ssh_port=$((nxos_last_octet + 2000))
nxos_https_port=$((nxos_last_octet + 4000))
nxos_http_port=$((nxos_last_octet + 8000))
nxos_netconf_port=$((nxos_last_octet + 3000))
iosxr_last_octet="${iosxr_ip##*.}"
iosxr_ssh_port=$((iosxr_last_octet + 2000))
iosxr_https_port=$((iosxr_last_octet + 4000))
iosxr_http_port=$((iosxr_last_octet + 8000))
iosxr_netconf_port=$((iosxr_last_octet + 3000))
iosxr_grpc_port=57400
iosxe_last_octet="${iosxe_ip##*.}"
iosxe_ssh_port=$((iosxe_last_octet + 2000))
iosxe_https_port=$((iosxe_last_octet + 4000))
iosxe_http_port=$((iosxe_last_octet + 8000))
iosxe_netconf_port=$((iosxe_last_octet + 3000))
ubuntu_last_octet="${ubuntu_ip##*.}"
ubuntu_ssh_port=$((ubuntu_last_octet + 2000))
# Destination host for port-forwarded access
dest_host="54.190.208.146"
out_file="$RUNNER_TEMP/inventory-${{ matrix.ansible_version }}.ini"
ansible localhost -c local -m template -a "src=tests/integration/labs/inventory.j2 dest=$out_file mode=0644" \
-e "ansible_host=$dest_host ansible_network_cli_ssh_type=$CLI_SSH_TYPE \
nxos_ssh_port=$nxos_ssh_port nxos_http_port=$nxos_http_port nxos_netconf_port=$nxos_netconf_port \
iosxr_netconf_port=$iosxr_netconf_port iosxr_grpc_port=$iosxr_grpc_port ubuntu_ssh_port=$ubuntu_ssh_port \
iosxe_http_port=$iosxe_http_port iosxr_ssh_port=$iosxr_ssh_port iosxe_ssh_port=$iosxe_ssh_port"
echo "inventory_path=$out_file" >> "$GITHUB_OUTPUT"
- name: DEBUG Print the ansible version
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug == 'true' || github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'debug') }}
run: ansible --version
- name: DEBUG inventory
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug == 'true' || github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'debug') }}
shell: bash
run: |
echo "Inventory path: ${{ steps.render_inventory.outputs.inventory_path }}"
echo
cat "${{ steps.render_inventory.outputs.inventory_path }}"
- name: DEBUG libssh and pylibssh versions
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug == 'true' || github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'debug') }}
shell: bash
run: python -c "from pylibsshext import __full_version__; print(__full_version__)"
- name: Run ansible-test network-integration - all
run: ansible-test network-integration --inventory "${{ steps.render_inventory.outputs.inventory_path }}" -vvvv
working-directory: ${{ steps.identify.outputs.collection_path }}
env:
LAB_NODES: ${{ needs.lab-create.outputs.lab_nodes_json }}
lab-destroy:
if: ${{ always() }}
needs: integration-tests
uses: ansible/ansible-content-actions/.github/workflows/cml_lab_destroy.yaml@main
secrets:
virl_host: ${{ secrets.VIRL_HOST }}
virl_username: ${{ secrets.VIRL_USERNAME }}
virl_password: ${{ secrets.VIRL_PASSWORD }}