-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Context
After completing HOM-23 (migrating VyOS image builds from Packer to vyos-build), we now have a build pipeline that produces both a raw disk image for production and an ISO with an extractable squashfs filesystem. This creates an opportunity to introduce integration testing for the VyOS gateway configuration using Containerlab.
Currently, VyOS configuration changes in infrastructure/network/vyos/configs/gateway.conf are validated only via:
- Ansible-lint and syntax checks (PR validation)
- Manual testing after deployment to production
This leaves a gap: we cannot validate that firewall rules actually block traffic, DHCP actually serves leases, or BGP neighbors are correctly configured until the config hits production.
Goal
Introduce a Containerlab-based integration test suite that validates the VyOS gateway configuration before it reaches production. Tests should run on PRs that modify VyOS configuration.
Technical Approach
1. Container Image from vyos-build
The vyos-build pipeline (from HOM-23) produces build/live/filesystem.squashfs as an intermediate artifact. This can be converted to a container image:
# Extract squashfs to tarball
sqfs2tar build/live/filesystem.squashfs > rootfs.tar
# Build container
docker build -t vyos-gateway:test -f Dockerfile.containerlab .Dockerfile.containerlab:
FROM scratch
ADD rootfs.tar /
RUN for service in getty.target auditd.service; do systemctl mask $service; done && \
systemctl disable kea-dhcp-ddns-server.service
HEALTHCHECK --start-period=10s CMD systemctl is-system-running
CMD ["/sbin/init"]This container uses the exact same rootfs as the production raw image, ensuring test fidelity.
2. Containerlab Topology
Create a minimal topology that simulates the lab network segments:
# infrastructure/network/vyos/tests/topology.clab.yml
name: vyos-gateway-test
topology:
nodes:
gateway:
kind: vyosnetworks_vyos
image: vyos-gateway:test
# Config is baked in via vyos-build flavor
# Simulated clients for functional tests
mgmt-client:
kind: linux
image: alpine:latest
exec:
- ip addr add 10.10.10.100/24 dev eth1
- ip route add default via 10.10.10.1
platform-client:
kind: linux
image: alpine:latest
exec:
- ip addr add 10.10.30.100/24 dev eth1
- ip route add default via 10.10.30.1
links:
- endpoints: ["gateway:eth1", "mgmt-client:eth1"] # VLAN 10 simulation
- endpoints: ["gateway:eth2", "platform-client:eth1"] # VLAN 30 simulation3. Test Suite (pytest + scrapli)
Use pytest with scrapli for SSH-based validation:
# infrastructure/network/vyos/tests/test_gateway.py
import pytest
from scrapli.driver.network import VyOSDriver
@pytest.fixture(scope="module")
def vyos():
conn = VyOSDriver(
host="clab-vyos-gateway-test-gateway",
auth_username="vyos",
auth_password="vyos",
auth_strict_key=False,
)
conn.open()
yield conn
conn.close()
class TestFirewallConfiguration:
def test_firewall_groups_exist(self, vyos):
result = vyos.send_command("show firewall group")
assert "HOME_NETWORK" in result.result
assert "LAB_NETWORKS" in result.result
assert "RFC1918" in result.result
def test_wan_to_lab_rules(self, vyos):
result = vyos.send_command("show firewall ipv4 name WAN_TO_LAB")
assert "default-action drop" in result.result
assert "Allow established/related" in result.result
def test_lab_to_wan_rules(self, vyos):
result = vyos.send_command("show firewall ipv4 name LAB_TO_WAN")
assert "Block new connections to home network" in result.result
class TestInterfaceConfiguration:
def test_vlan_interfaces_configured(self, vyos):
result = vyos.send_command("show interfaces")
assert "eth5.10" in result.result # LAB_MGMT
assert "eth5.20" in result.result # LAB_PROV
assert "eth5.30" in result.result # LAB_PLATFORM
assert "eth5.50" in result.result # LAB_SERVICE
def test_interface_addresses(self, vyos):
result = vyos.send_command("show interfaces ethernet eth5 vif 10")
assert "10.10.10.1/24" in result.result
class TestServicesConfiguration:
def test_dhcp_server_configured(self, vyos):
result = vyos.send_command("show dhcp server leases")
# Command should succeed (service running)
assert result.failed is False
def test_dns_forwarding_configured(self, vyos):
result = vyos.send_command("show dns forwarding statistics")
assert result.failed is False
def test_bgp_neighbors_configured(self, vyos):
result = vyos.send_command("show protocols bgp neighbor")
assert "10.10.30.10" in result.result # platform-cp-1
assert "10.10.30.11" in result.result # platform-cp-2
assert "10.10.30.12" in result.result # platform-cp-3
class TestNATConfiguration:
def test_masquerade_rule_exists(self, vyos):
result = vyos.send_command("show nat source rules")
assert "masquerade" in result.result.lower()
assert "10.10.0.0/16" in result.result4. GitHub Actions Integration
Extend the vyos-build workflow to run integration tests on PRs:
# In .github/workflows/vyos-build.yml (or new vyos-integration-test.yml)
integration-test:
needs: build
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download container image
uses: actions/download-artifact@v4
with:
name: vyos-container-image
- name: Load container image
run: docker load -i vyos-gateway.tar
- name: Install Containerlab
run: bash -c "$(curl -sL https://get.containerlab.dev)"
- name: Install test dependencies
run: pip install pytest scrapli
- name: Deploy topology
run: sudo containerlab deploy -t infrastructure/network/vyos/tests/topology.clab.yml
- name: Wait for VyOS boot
run: |
echo "Waiting for VyOS to boot..."
sleep 90
# Optionally: poll for SSH availability
- name: Run integration tests
run: pytest infrastructure/network/vyos/tests/ -v --tb=short
- name: Cleanup
if: always()
run: sudo containerlab destroy -t infrastructure/network/vyos/tests/topology.clab.yml --cleanupImplementation Steps
- Extend vyos-build workflow to produce and upload container image artifact
- Create Containerlab topology file at
infrastructure/network/vyos/tests/topology.clab.yml - Create Dockerfile.containerlab for container image build
- Write pytest test suite covering firewall, interfaces, services, NAT, and BGP
- Add integration-test job to GitHub Actions workflow
- Document the testing approach in ADR-003 or a new testing doc
Considerations
VyOS Boot Time
VyOS containers take 45-90 seconds to fully boot. The workflow should include adequate wait time or poll for readiness.
Privileged Containers
VyOS requires --privileged mode. GitHub-hosted runners support this.
Interface Mapping
Containerlab uses eth0 for management. The topology must map test interfaces to eth1+ to avoid conflicts with the production config's interface expectations.
Test Scope
Start with configuration validation tests (verifying config is loaded correctly). Functional tests (e.g., actually testing DHCP lease acquisition) can be added later.
Acceptance Criteria
- Container image is built from vyos-build squashfs artifact
- Containerlab topology deploys successfully with gateway + test clients
- pytest suite validates: firewall rules, interface config, DHCP, DNS, BGP, NAT
- Integration tests run automatically on PRs modifying
infrastructure/network/vyos/** - Tests complete within reasonable time (~3-5 minutes)
- Documentation updated to reflect new testing capability
References
- Blocked by: HOM-23 (vyos-build migration)
- VyOS config:
infrastructure/network/vyos/configs/gateway.conf - Containerlab VyOS docs: https://containerlab.dev/manual/kinds/vyosnetworks_vyos/
- ADR-003:
docs/architecture/09_design_decisions/003_vyos_gitops.md