Add a release pipeline including tests for Bird2 and VPP
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
clab-*
|
||||
**/*.bak
|
||||
tests/.venv/
|
||||
tests/out/
|
||||
|
||||
264
BUILDING.md
264
BUILDING.md
@@ -1,85 +1,20 @@
|
||||
# Building vpp-containerlab
|
||||
|
||||
This docker container creates a VPP instance based on the latest VPP release. It starts up as per
|
||||
normal, using /etc/vpp/startup.conf (which Containerlab might replace when it starts its
|
||||
containers). Once started, it'll execute `/etc/vpp/bootstrap.vpp` within the dataplane. There are
|
||||
two relevant files:
|
||||
This document describes how to build, test and release the `vpp-containerlab` Docker image.
|
||||
The image is built natively on two machines and combined into a multi-arch manifest:
|
||||
|
||||
1. `clab.vpp` -- generated by `files/init-container.sh`. Its purpose is to bind the `veth`
|
||||
interfaces that containerlab has added to the container into the VPP dataplane (see below).
|
||||
1. `vppcfg.vpp` -- generated by `files/init-container.sh`. Its purpose is to read the user
|
||||
specified `vppcfg.yaml` file and convert it into VPP CLI commands. If no YAML file is
|
||||
specified, or if it is not syntactically valid, an empty file is generated instead.
|
||||
- `summer` — amd64, Linux (local machine)
|
||||
- `jessica-orb` — arm64, OrbStack VM on macOS, reachable via `ssh jessica-orb`
|
||||
|
||||
For Containerlab users who wish to have more control over their VPP bootstrap, it's possible to
|
||||
bind-mount `/etc/vpp/bootstrap.vpp`.
|
||||
The pipeline sideloads locally-built VPP `.deb` packages rather than pulling from packagecloud,
|
||||
so VPP must be compiled on both machines before building the image.
|
||||
|
||||
## Building
|
||||
## Prerequisites
|
||||
|
||||
To build, this container uses Docker's `buildx`, for which on Debian Bookworm it's required to use
|
||||
the upstream (docker.com) packages described [[here](https://docs.docker.com/engine/install/debian/)].
|
||||
To allow the buildx to build for multi-arch, it's also required to install the Qemu `binfmt`
|
||||
emulators, with:
|
||||
### SSH access to jessica-orb
|
||||
|
||||
```bash
|
||||
docker run --privileged --rm tonistiigi/binfmt --install all
|
||||
```
|
||||
|
||||
Then, ongoing builds can be cross-platform and take about 1500 seconds on an AMD64 i7-12700T
|
||||
The buildx invocation will build 'latest' and then tag it with the current VPP package release,
|
||||
which you can get from `vppcfg show version`, like so:
|
||||
|
||||
```bash
|
||||
IMG=git.ipng.ch/ipng/vpp-containerlab
|
||||
ARCH=linux/$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
|
||||
TAG=latest
|
||||
docker buildx build --load --platform $ARCH \
|
||||
--tag $IMG:$TAG -f docker/Dockerfile docker/
|
||||
|
||||
TAG=v25.10-release
|
||||
docker buildx build --load --build-arg REPO=2510 --platform $ARCH \
|
||||
--tag $IMG:$TAG -f docker/Dockerfile docker/
|
||||
```
|
||||
|
||||
### Sideloading locally built VPP packages
|
||||
|
||||
Instead of pulling VPP from packagecloud, you can sideload locally built `.deb` packages using
|
||||
Docker buildx's `--build-context` flag. This is useful for testing unreleased VPP builds or
|
||||
working around version-specific issues (for example, VPP 25.10 fails to start on kernels that
|
||||
do not expose NUMA topology via sysfs, such as OrbStack on Apple Silicon; VPP 26.06+ fixes this).
|
||||
|
||||
Point `--build-context vppdebs=<path>` at a directory containing `libvppinfra_*.deb`,
|
||||
`vpp_*.deb`, and `vpp-plugin-core_*.deb`. If the context is not provided, the build falls back
|
||||
to packagecloud as normal. The `.deb` files are bind-mounted during the build and never stored
|
||||
in an image layer. **Note:** the directory must contain `.deb` files for exactly one VPP version;
|
||||
if multiple versions are present the glob patterns will match ambiguously and the build will fail.
|
||||
|
||||
```bash
|
||||
# Build from locally compiled VPP packages (e.g. from ~/src/vpp after make pkg-deb):
|
||||
IMG=git.ipng.ch/ipng/vpp-containerlab
|
||||
ARCH=linux/$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
|
||||
VPPDEBS=~/src/vpp/build-root
|
||||
docker buildx build --load --platform $ARCH \
|
||||
--build-context vppdebs=$VPPDEBS \
|
||||
--tag $IMG:latest -f docker/Dockerfile docker/
|
||||
|
||||
# Build from packagecloud as normal (no --build-context needed):
|
||||
docker buildx build --load --platform $ARCH \
|
||||
--tag $IMG:latest -f docker/Dockerfile docker/
|
||||
```
|
||||
|
||||
### Multiarch
|
||||
|
||||
Building a combined `linux/amd64` + `linux/arm64` manifest requires two machines building natively
|
||||
— one per architecture. The setup below uses `summer` (amd64, Linux) and `jessica` (arm64, macOS
|
||||
running OrbStack). **VPP must be compiled on each machine before building the Docker image**, because
|
||||
the sideloader mounts locally built `.deb` files that are architecture-specific.
|
||||
|
||||
#### Setup
|
||||
|
||||
On `jessica`, the Docker daemon runs inside OrbStack's Linux VM. Expose its SSH port so `summer`
|
||||
can reach it. OrbStack listens on `127.0.0.1:32222`; add a jump-host entry to `~/.ssh/config` on
|
||||
`summer`:
|
||||
The Docker daemon on `jessica` runs inside OrbStack's Linux VM. OrbStack listens on
|
||||
`127.0.0.1:32222`; add a jump-host entry to `~/.ssh/config` on `summer` to reach it:
|
||||
|
||||
```
|
||||
Host jessica-orb
|
||||
@@ -107,118 +42,127 @@ ssh jessica-orb 'uname -m && docker info | head -3'
|
||||
# expected: aarch64
|
||||
```
|
||||
|
||||
Create the multiarch builder (run once on `summer`):
|
||||
### One-time setup
|
||||
|
||||
Install the Robot Framework venv for running tests:
|
||||
|
||||
```bash
|
||||
docker buildx create --name multiarch --driver docker-container --platform linux/amd64 --node summer-amd64
|
||||
docker buildx create --append --name multiarch --driver docker-container --platform linux/arm64 --node jessica-arm64 ssh://jessica-orb
|
||||
docker buildx inspect multiarch --bootstrap
|
||||
make venv
|
||||
```
|
||||
|
||||
#### Build
|
||||
This only needs to be re-run if `tests/requirements.txt` changes.
|
||||
|
||||
Build VPP on both machines first (`make pkg-deb` in your VPP source tree on both `summer` and the
|
||||
OrbStack VM on `jessica`). When sideloading `.deb` files, Docker sends the build context from the
|
||||
client to every builder node — meaning `summer`'s amd64 debs would be sent to `jessica-orb` for
|
||||
the arm64 build (wrong arch). The solution is to build each platform separately on its native
|
||||
machine and combine them into a manifest.
|
||||
### Before every release
|
||||
|
||||
Build VPP on both machines (`make pkg-deb` in your VPP source tree on both `summer` and the
|
||||
OrbStack VM on `jessica`), then verify both machines have a consistent set of `.deb` packages:
|
||||
|
||||
```bash
|
||||
IMG=git.ipng.ch/ipng/vpp-containerlab
|
||||
VPPDEBS=~/src/vpp/build-root
|
||||
|
||||
# Step 1: build amd64 on summer, push with platform tag
|
||||
docker buildx build --platform linux/amd64 \
|
||||
--no-cache --build-context vppdebs=$VPPDEBS \
|
||||
--push --tag $IMG:latest-amd64 \
|
||||
-f docker/Dockerfile docker/
|
||||
|
||||
# Step 2: build arm64 natively on jessica-orb, push with platform tag
|
||||
# (repo and VPP debs must be present on jessica-orb at the same paths)
|
||||
# Note: $IMG and $VPPDEBS expand on summer before being sent over SSH -- set them first.
|
||||
ssh jessica-orb "cd ~/src/vpp-containerlab && \
|
||||
docker buildx build --platform linux/arm64 \
|
||||
--no-cache --build-context vppdebs=$VPPDEBS \
|
||||
--push --tag $IMG:latest-arm64 \
|
||||
-f docker/Dockerfile docker/"
|
||||
|
||||
# Step 3: combine into a single multi-arch manifest and push in one step
|
||||
# (docker buildx build --push produces manifest lists, so use imagetools, not docker manifest)
|
||||
docker buildx imagetools create \
|
||||
--tag $IMG:latest \
|
||||
$IMG:latest-amd64 \
|
||||
$IMG:latest-arm64
|
||||
make preflight
|
||||
```
|
||||
|
||||
## Testing standalone container
|
||||
This checks that `~/src/vpp/build-root` on each machine contains exactly one version of each
|
||||
required package and that the version on `summer` matches the version on `jessica-orb`.
|
||||
Override the path if your build root is elsewhere:
|
||||
|
||||
```bash
|
||||
docker network create --driver=bridge clab-network --subnet=192.0.2.0/24 \
|
||||
--ipv6 --subnet=2001:db8::/64
|
||||
docker rm clab-pim
|
||||
docker run --cap-add=NET_ADMIN --cap-add=SYS_NICE --cap-add=SYS_PTRACE \
|
||||
--device=/dev/net/tun:/dev/net/tun \
|
||||
--device=/dev/vhost-net:/dev/vhost-net \
|
||||
--privileged --name clab-pim \
|
||||
git.ipng.ch/ipng/vpp-containerlab:latest
|
||||
docker network connect clab-network clab-pim
|
||||
make preflight VPPDEBS=~/src/vpp/other-build-root
|
||||
```
|
||||
|
||||
### A note on DPDK
|
||||
## Release pipeline
|
||||
|
||||
The full pipeline runs in this order:
|
||||
|
||||
DPDK will be disabled by default as it requires hugepages and VFIO and/or UIO to use physical
|
||||
network cards. If DPDK at some future point is desired, mapping VFIO can be done by adding this:
|
||||
```
|
||||
--device=/dev/vfio/vfio:/dev/vfio/vfio
|
||||
preflight → build → test → push → release
|
||||
```
|
||||
|
||||
or in Containerlab, using the `devices` feature:
|
||||
|
||||
```yaml
|
||||
my-node:
|
||||
image: git.ipng.ch/ipng/vpp-containerlab:latest
|
||||
kind: fdio_vpp
|
||||
devices:
|
||||
- /dev/vfio/vfio
|
||||
- /dev/net/tun
|
||||
- /dev/vhost-net
|
||||
```
|
||||
|
||||
If using DPDK in a container, one of the userspace IO kernel drivers must be loaded in the host
|
||||
kernel. Options are `igb_uio`, `vfio_pci`, or `uio_pci_generic`:
|
||||
Run everything in one shot:
|
||||
|
||||
```bash
|
||||
$ sudo modprobe igb_uio
|
||||
$ sudo modprobe vfio_pci
|
||||
$ sudo modprobe uio_pci_generic
|
||||
make all
|
||||
```
|
||||
|
||||
Particularly the VFIO driver needs to be present before one can attempt to bindmount
|
||||
`/dev/vfio/vfio` into the container!
|
||||
Or step through it manually:
|
||||
|
||||
## Configuring VPP
|
||||
| Step | Command | What it does |
|
||||
|------|---------|--------------|
|
||||
| 1 | `make preflight` | Validate VPP debs on summer and jessica-orb |
|
||||
| 2 | `make build-amd64` | Build image locally for amd64 |
|
||||
| 3 | `make test-amd64` | Run e2e tests against the amd64 image |
|
||||
| 4 | `make sync-arm64` | Rsync working tree to jessica-orb |
|
||||
| 5 | `make build-arm64` | Build image on jessica-orb for arm64 |
|
||||
| 6 | `make test-arm64` | Run e2e tests on jessica-orb against the arm64 image |
|
||||
| 7 | `make push-amd64` | Tag and push `:latest-amd64` to the registry |
|
||||
| 8 | `make push-arm64` | Tag and push `:latest-arm64` to the registry |
|
||||
| 9 | `make release` | Combine into a single `:latest` multi-arch manifest |
|
||||
|
||||
When Containerlab starts the docker containers, it'll offer one or more `veth` point to point
|
||||
network links, which will show up as `eth1` and further. `eth0` is the default NIC that belongs to
|
||||
the management plane in Containerlab (the one which you'll see with `containerlab inspect`). Before
|
||||
VPP can use these `veth` interfaces, it needs to bind them, like so:
|
||||
Convenience targets:
|
||||
|
||||
```bash
|
||||
docker exec -it clab-pim vppctl
|
||||
make build # steps 2+4+5 (both platforms)
|
||||
make test # steps 3+6 (both platforms)
|
||||
make push # steps 7+8 (both platforms)
|
||||
```
|
||||
|
||||
and then within the VPP control shell:
|
||||
### Promoting to :stable
|
||||
|
||||
```
|
||||
create host-interface v2 name eth1
|
||||
set interface name host-eth1 eth1
|
||||
set interface mtu 1500 eth1
|
||||
set interface ip address eth1 192.0.2.2/24
|
||||
set interface ip address eth1 2001:db8::2/64
|
||||
set interface state eth1 up
|
||||
`:stable` is only promoted **after** a successful `make all` — meaning both amd64 and arm64
|
||||
have been built, tested, pushed and combined into `:latest`. Do not run `make stable` unless
|
||||
the full pipeline completed without errors.
|
||||
|
||||
```bash
|
||||
make all && make stable
|
||||
```
|
||||
|
||||
Containerlab will attach these `veth` pairs to the container, and replace our Docker CMD with one
|
||||
that waits for all of these interfaces to be added (typically called `if-wait.sh`). In our own CMD,
|
||||
we then generate a config file called `/etc/vpp/clab.vpp` which contains the necessary VPP commands
|
||||
to take control over these `veth` pairs.
|
||||
`make stable` points `:stable` at the same manifest as the current `:latest-amd64` and
|
||||
`:latest-arm64`, so it is always in sync with a fully tested release.
|
||||
|
||||
## Running a single test suite
|
||||
|
||||
Pass `TEST=` to restrict which suite is run:
|
||||
|
||||
```bash
|
||||
make test-amd64 TEST=tests/01-vpp-ospf
|
||||
make test TEST=tests/02-vpp-frr
|
||||
```
|
||||
|
||||
The default is `tests/` (all suites).
|
||||
|
||||
## Debugging test failures
|
||||
|
||||
**Read the HTML log** — written after every run regardless of outcome:
|
||||
|
||||
```bash
|
||||
xdg-open tests/out/tests-docker-log.html
|
||||
```
|
||||
|
||||
**Deploy the topology manually** to keep containers running for inspection:
|
||||
|
||||
```bash
|
||||
IMAGE=git.ipng.ch/ipng/vpp-containerlab:latest-amd64-test \
|
||||
containerlab deploy -t tests/01-vpp-ospf/e2e-lab/vpp.clab.yml
|
||||
```
|
||||
|
||||
Then inspect live state:
|
||||
|
||||
```bash
|
||||
# OSPF neighbour state
|
||||
containerlab exec -t tests/01-vpp-ospf/e2e-lab/vpp.clab.yml \
|
||||
--label clab-node-name=vpp1 --cmd "birdc show ospf neighbor"
|
||||
|
||||
# Manual ping
|
||||
containerlab exec -t tests/01-vpp-ospf/e2e-lab/vpp.clab.yml \
|
||||
--label clab-node-name=client1 --cmd "ping -c 5 10.82.98.82"
|
||||
|
||||
# Tear down when done
|
||||
containerlab destroy -t tests/01-vpp-ospf/e2e-lab/vpp.clab.yml --cleanup
|
||||
```
|
||||
|
||||
**Common cause — OSPF convergence time:** 100% ping loss usually means routing is not up yet.
|
||||
Tune the `Sleep` duration in the relevant `.robot` file by deploying manually and watching
|
||||
`birdc show ospf neighbor` (or `vtysh -c "show ip ospf neighbor"` for FRR) until all
|
||||
neighbours reach state `Full`.
|
||||
|
||||
**Increase robot verbosity:** add `--loglevel DEBUG` to the `robot` invocation in
|
||||
`tests/rf-run.sh` temporarily.
|
||||
|
||||
131
Makefile
Normal file
131
Makefile
Normal file
@@ -0,0 +1,131 @@
|
||||
IMG := git.ipng.ch/ipng/vpp-containerlab
|
||||
BUILDHOST := jessica-orb
|
||||
BUILDDIR := ~/src/.vpp-containerlab-build
|
||||
VPPDEBS := $(HOME)/src/vpp/build-root
|
||||
TEST ?= tests/
|
||||
|
||||
.PHONY: all help preflight build build-amd64 build-arm64 sync-arm64 test test-amd64 test-arm64 \
|
||||
push push-amd64 push-arm64 release stable venv
|
||||
|
||||
help:
|
||||
@echo "vpp-containerlab build, test and release"
|
||||
@echo ""
|
||||
@echo "Typical workflow:"
|
||||
@echo " 1. make venv Set up local Robot Framework venv (once, or after requirements change)"
|
||||
@echo " 2. make preflight Verify VPP debs in VPPDEBS= on summer and jessica-orb"
|
||||
@echo " 3. make build-amd64 Build image locally for amd64 (sideloading VPPDEBS)"
|
||||
@echo " 4. make test-amd64 Run e2e tests locally against the amd64 image"
|
||||
@echo " 5. make sync-arm64 Rsync working tree to jessica-orb and set up venv there"
|
||||
@echo " 6. make build-arm64 Build image on jessica-orb for arm64 (sideloading VPPDEBS)"
|
||||
@echo " 7. make test-arm64 Run e2e tests on jessica-orb against the arm64 image"
|
||||
@echo " 8. make push-amd64 Tag and push :latest-amd64 to the registry"
|
||||
@echo " 9. make push-arm64 Tag and push :latest-arm64 to the registry (runs on jessica-orb)"
|
||||
@echo " 10. make release Combine into a single :latest multi-arch manifest"
|
||||
@echo ""
|
||||
@echo " make all Run steps 2-10 in one go (venv must already exist)"
|
||||
@echo " make build Run steps 3+5+6 (sync-arm64 + both builds)"
|
||||
@echo " make test Run steps 4+7 (both test suites)"
|
||||
@echo " make push Run steps 8+9 (both pushes)"
|
||||
@echo " make release Run step 10 (publish into a multi-arch manifest)"
|
||||
@echo " make stable When all tests pass on amd64+arm64, push this ':latest' as :stable'"
|
||||
@echo ""
|
||||
@echo "Variables (override on command line):"
|
||||
@echo " VPPDEBS=~/src/vpp/build-root Directory of locally-built VPP .deb packages"
|
||||
@echo " TEST=tests/02-vpp-frr Run only a specific test suite (default: all)"
|
||||
|
||||
# Build both platforms, test both, push both, then combine into :latest.
|
||||
all: preflight build test push release
|
||||
|
||||
build: build-amd64 sync-arm64 build-arm64
|
||||
|
||||
test: test-amd64 test-arm64
|
||||
|
||||
push: push-amd64 push-arm64
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Preflight — validate VPP debs on summer and jessica-orb
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# Check locally, then pipe the same script to jessica-orb over SSH,
|
||||
# passing the local version so jessica-orb can assert both machines match.
|
||||
preflight:
|
||||
python3 scripts/check-vppdebs.py $(VPPDEBS)
|
||||
$(eval VPP_VERSION := $(shell python3 scripts/check-vppdebs.py --print-version $(VPPDEBS)))
|
||||
ssh $(BUILDHOST) python3 - --assert-version $(VPP_VERSION) $(VPPDEBS) < scripts/check-vppdebs.py
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Local venv (summer)
|
||||
# -------------------------------------------------------------------------
|
||||
tests/.venv: tests/requirements.txt
|
||||
python3 -m venv tests/.venv
|
||||
tests/.venv/bin/pip install -q -r tests/requirements.txt
|
||||
|
||||
venv: tests/.venv
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# amd64 — runs locally on summer
|
||||
# -------------------------------------------------------------------------
|
||||
build-amd64:
|
||||
docker buildx build --no-cache --load --platform linux/amd64 \
|
||||
--build-context vppdebs=$(VPPDEBS) \
|
||||
--tag $(IMG):latest-amd64-test \
|
||||
-f docker/Dockerfile docker/
|
||||
|
||||
test-amd64: tests/.venv
|
||||
IMAGE=$(IMG):latest-amd64-test tests/rf-run.sh docker $(TEST)
|
||||
|
||||
push-amd64:
|
||||
docker tag $(IMG):latest-amd64-test $(IMG):latest-amd64
|
||||
docker push $(IMG):latest-amd64
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# arm64 — runs on jessica-orb via rsync + SSH
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# Wipe and re-sync summer's working tree to a stable directory on jessica-orb,
|
||||
# then set up the robot venv there.
|
||||
sync-arm64:
|
||||
@case "$(BUILDDIR)" in \
|
||||
.*|/*) echo "ERROR: BUILDDIR '$(BUILDDIR)' must not start with '.' or '/'" >&2; exit 1;; \
|
||||
esac
|
||||
ssh $(BUILDHOST) "rm -rf $(BUILDDIR) && mkdir -p $(BUILDDIR)"
|
||||
rsync -a --exclude='.git' --exclude='tests/.venv' --exclude='tests/out' \
|
||||
./ $(BUILDHOST):$(BUILDDIR)/
|
||||
ssh $(BUILDHOST) "cd $(BUILDDIR) && \
|
||||
python3 -m venv tests/.venv && \
|
||||
tests/.venv/bin/pip install -q -r tests/requirements.txt"
|
||||
|
||||
build-arm64:
|
||||
ssh $(BUILDHOST) "cd $(BUILDDIR) && \
|
||||
docker buildx build --no-cache --load --platform linux/arm64 \
|
||||
--build-context vppdebs=$(VPPDEBS) \
|
||||
--tag $(IMG):latest-arm64-test \
|
||||
-f docker/Dockerfile docker/"
|
||||
|
||||
test-arm64:
|
||||
ssh $(BUILDHOST) "cd $(BUILDDIR) && \
|
||||
IMAGE=$(IMG):latest-arm64-test \
|
||||
tests/rf-run.sh docker $(TEST)"
|
||||
|
||||
push-arm64:
|
||||
ssh $(BUILDHOST) "docker tag $(IMG):latest-arm64-test $(IMG):latest-arm64 && \
|
||||
docker push $(IMG):latest-arm64"
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Release — combine amd64 + arm64 into a single :latest manifest
|
||||
# -------------------------------------------------------------------------
|
||||
release:
|
||||
docker buildx imagetools create \
|
||||
--tag $(IMG):latest \
|
||||
$(IMG):latest-amd64 \
|
||||
$(IMG):latest-arm64
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Stable — mark latest release as stable. Only do this if all tests pass
|
||||
# -------------------------------------------------------------------------
|
||||
stable:
|
||||
docker buildx imagetools create \
|
||||
--tag $(IMG):stable \
|
||||
$(IMG):latest-amd64 \
|
||||
$(IMG):latest-arm64
|
||||
118
scripts/check-vppdebs.py
Executable file
118
scripts/check-vppdebs.py
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Validate a directory of locally-built VPP .deb packages before a Docker build.
|
||||
|
||||
Checks:
|
||||
- The directory exists
|
||||
- Exactly one *.changes file
|
||||
- Exactly one *.buildinfo file
|
||||
- Exactly one of each required .deb package
|
||||
- All packages carry the same version string
|
||||
- Optionally: version matches an expected value (for cross-machine consistency)
|
||||
|
||||
Usage:
|
||||
check-vppdebs.py [--print-version] [--assert-version VERSION] [directory]
|
||||
|
||||
--print-version Print only the detected version string and exit (no other output).
|
||||
--assert-version VER After all checks pass, assert the detected version equals VER.
|
||||
Use this to verify summer and jessica-orb have the same build.
|
||||
directory Path to check (default: ~/src/vpp/build-root).
|
||||
"""
|
||||
|
||||
import sys
|
||||
import glob
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
REQUIRED_DEBS = [
|
||||
"libvppinfra_*.deb",
|
||||
"python3-vpp-api_*.deb",
|
||||
"vpp_*.deb",
|
||||
"vpp-crypto-engines_*.deb",
|
||||
"vpp-plugin-core_*.deb",
|
||||
]
|
||||
|
||||
def find(directory, pattern):
|
||||
return sorted(glob.glob(str(directory / pattern)))
|
||||
|
||||
def version_from_deb(path):
|
||||
"""Extract the version field from a deb filename: name_VERSION_arch.deb"""
|
||||
return Path(path).stem.split("_")[1]
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument("--print-version", action="store_true")
|
||||
parser.add_argument("--assert-version", metavar="VERSION", default=None)
|
||||
parser.add_argument("directory", nargs="?", default="~/src/vpp/build-root")
|
||||
args = parser.parse_args()
|
||||
|
||||
directory = Path(args.directory).expanduser()
|
||||
errors = []
|
||||
versions = []
|
||||
|
||||
if not args.print_version:
|
||||
print(f"Checking VPP debs in: {directory}")
|
||||
|
||||
if not directory.is_dir():
|
||||
print(f" ERROR: directory does not exist: {directory}")
|
||||
sys.exit(1)
|
||||
|
||||
# *.changes
|
||||
changes = find(directory, "*.changes")
|
||||
if len(changes) == 1:
|
||||
if not args.print_version:
|
||||
print(f" OK changes : {Path(changes[0]).name}")
|
||||
else:
|
||||
errors.append(f"expected exactly 1 *.changes, found {len(changes)}: {[Path(f).name for f in changes]}")
|
||||
|
||||
# *.buildinfo
|
||||
buildinfo = find(directory, "*.buildinfo")
|
||||
if len(buildinfo) == 1:
|
||||
if not args.print_version:
|
||||
print(f" OK buildinfo : {Path(buildinfo[0]).name}")
|
||||
else:
|
||||
errors.append(f"expected exactly 1 *.buildinfo, found {len(buildinfo)}: {[Path(f).name for f in buildinfo]}")
|
||||
|
||||
# required debs
|
||||
for pattern in REQUIRED_DEBS:
|
||||
matches = find(directory, pattern)
|
||||
if len(matches) == 1:
|
||||
ver = version_from_deb(matches[0])
|
||||
versions.append(ver)
|
||||
if not args.print_version:
|
||||
print(f" OK {pattern:<30s}: {Path(matches[0]).name}")
|
||||
else:
|
||||
errors.append(f"expected exactly 1 {pattern}, found {len(matches)}: {[Path(f).name for f in matches]}")
|
||||
|
||||
# version consistency within this directory
|
||||
if versions and len(set(versions)) > 1:
|
||||
errors.append(f"debs carry mixed versions: {sorted(set(versions))}")
|
||||
|
||||
if errors:
|
||||
if not args.print_version:
|
||||
print()
|
||||
for e in errors:
|
||||
print(f" ERROR: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
detected = versions[0] if versions else None
|
||||
|
||||
if args.print_version:
|
||||
print(detected or "")
|
||||
sys.exit(0)
|
||||
|
||||
print(f" OK version : {detected}")
|
||||
|
||||
# cross-machine version assertion
|
||||
if args.assert_version:
|
||||
if detected == args.assert_version:
|
||||
print(f" OK matches summer : {detected}")
|
||||
else:
|
||||
print(f" ERROR: version mismatch: this machine={detected}, summer={args.assert_version}")
|
||||
sys.exit(1)
|
||||
|
||||
print()
|
||||
print("Preflight OK.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
57
tests/01-vpp-bird/01-e2e-lab.robot
Normal file
57
tests/01-vpp-bird/01-e2e-lab.robot
Normal file
@@ -0,0 +1,57 @@
|
||||
*** Settings ***
|
||||
Library OperatingSystem
|
||||
Resource ../ssh.robot
|
||||
Resource ../common.robot
|
||||
|
||||
Suite Teardown Run Keyword Cleanup
|
||||
|
||||
|
||||
*** Variables ***
|
||||
${lab-name} e2e-vpp
|
||||
${lab-file-name} e2e-lab/vpp.clab.yml
|
||||
${runtime} docker
|
||||
|
||||
|
||||
*** Test Cases ***
|
||||
Deploy ${lab-name} lab
|
||||
Log ${CURDIR}
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} deploy -t ${CURDIR}/${lab-file-name}
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
|
||||
Pause to let OSPF converge
|
||||
Sleep 20s
|
||||
|
||||
Check BFD Adjacencies
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file-name} --label clab-node-name\=vpp2 --cmd "birdc show bfd ses"
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
Should Match Regexp ${output} (?m)fe80::.*eth2.*Up
|
||||
Should Match Regexp ${output} (?m)10\.82\.98\..*eth2.*Up
|
||||
|
||||
Check OSPF IPv4 Adjacency
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file-name} --label clab-node-name\=vpp1 --cmd "birdc show ospf nei ospf4"
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
Should Match Regexp ${output} (?m)Full/PtP.*eth2
|
||||
|
||||
Check OSPF IPv6 Adjacency
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file-name} --label clab-node-name\=vpp2 --cmd "birdc show ospf nei ospf6"
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
Should Match Regexp ${output} (?m)Full/PtP.*eth2
|
||||
|
||||
Ensure client1 can ping client2
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file-name} --label clab-node-name\=client1 --cmd "ping -c 5 10.82.98.82"
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
Should Contain ${output} 5 packets transmitted, 4 packets received, 20% packet loss
|
||||
|
||||
*** Keywords ***
|
||||
Cleanup
|
||||
Run ${CLAB_BIN} --runtime ${runtime} destroy -t ${CURDIR}/${lab-file-name} --cleanup
|
||||
19
tests/01-vpp-bird/e2e-lab/config/vpp1/bird-local.conf
Normal file
19
tests/01-vpp-bird/e2e-lab/config/vpp1/bird-local.conf
Normal file
@@ -0,0 +1,19 @@
|
||||
protocol bfd bfd1 {
|
||||
interface "eth2" { interval 100 ms; multiplier 30; };
|
||||
}
|
||||
|
||||
protocol ospf v2 ospf4 {
|
||||
ipv4 { import all; export all; };
|
||||
area 0 {
|
||||
interface "loop0" { stub yes; };
|
||||
interface "eth2" { type pointopoint; cost 10; bfd on; };
|
||||
};
|
||||
}
|
||||
|
||||
protocol ospf v3 ospf6 {
|
||||
ipv6 { import all; export all; };
|
||||
area 0 {
|
||||
interface "loop0" { stub yes; };
|
||||
interface "eth2" { type pointopoint; cost 10; bfd on; };
|
||||
};
|
||||
}
|
||||
16
tests/01-vpp-bird/e2e-lab/config/vpp1/vppcfg.yaml
Normal file
16
tests/01-vpp-bird/e2e-lab/config/vpp1/vppcfg.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
interfaces:
|
||||
eth1:
|
||||
description: "To client1"
|
||||
mtu: 1500
|
||||
lcp: eth1
|
||||
addresses: [10.82.98.65/28, 2001:db8:8298:101::1/64]
|
||||
eth2:
|
||||
description: "To vpp2"
|
||||
mtu: 9216
|
||||
lcp: eth2
|
||||
addresses: [10.82.98.16/31, 2001:db8:8298:1::1/64]
|
||||
loopbacks:
|
||||
loop0:
|
||||
description: "vpp1"
|
||||
lcp: loop0
|
||||
addresses: [10.82.98.0/32, 2001:db8:8298::/128]
|
||||
19
tests/01-vpp-bird/e2e-lab/config/vpp2/bird-local.conf
Normal file
19
tests/01-vpp-bird/e2e-lab/config/vpp2/bird-local.conf
Normal file
@@ -0,0 +1,19 @@
|
||||
protocol bfd bfd1 {
|
||||
interface "eth2" { interval 100 ms; multiplier 30; };
|
||||
}
|
||||
|
||||
protocol ospf v2 ospf4 {
|
||||
ipv4 { import all; export all; };
|
||||
area 0 {
|
||||
interface "loop0" { stub yes; };
|
||||
interface "eth2" { type pointopoint; cost 10; bfd on; };
|
||||
};
|
||||
}
|
||||
|
||||
protocol ospf v3 ospf6 {
|
||||
ipv6 { import all; export all; };
|
||||
area 0 {
|
||||
interface "loop0" { stub yes; };
|
||||
interface "eth2" { type pointopoint; cost 10; bfd on; };
|
||||
};
|
||||
}
|
||||
16
tests/01-vpp-bird/e2e-lab/config/vpp2/vppcfg.yaml
Normal file
16
tests/01-vpp-bird/e2e-lab/config/vpp2/vppcfg.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
interfaces:
|
||||
eth1:
|
||||
description: "To client2"
|
||||
mtu: 1500
|
||||
lcp: eth1
|
||||
addresses: [10.82.98.81/28, 2001:db8:8298:102::1/64]
|
||||
eth2:
|
||||
description: "To vpp1"
|
||||
mtu: 9216
|
||||
lcp: eth2
|
||||
addresses: [10.82.98.17/31, 2001:db8:8298:1::2/64]
|
||||
loopbacks:
|
||||
loop0:
|
||||
description: "vpp2"
|
||||
lcp: loop0
|
||||
addresses: [10.82.98.1/32, 2001:db8:8298::1/128]
|
||||
38
tests/01-vpp-bird/e2e-lab/vpp.clab.yml
Normal file
38
tests/01-vpp-bird/e2e-lab/vpp.clab.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
name: e2e-vpp
|
||||
|
||||
topology:
|
||||
kinds:
|
||||
fdio_vpp:
|
||||
image: ${IMAGE}
|
||||
startup-config: config/__clabNodeName__/vppcfg.yaml
|
||||
binds:
|
||||
- config/__clabNodeName__/bird-local.conf:/config/bird/bird-local.conf:ro
|
||||
linux:
|
||||
image: alpine:latest
|
||||
|
||||
nodes:
|
||||
vpp1:
|
||||
kind: fdio_vpp
|
||||
vpp2:
|
||||
kind: fdio_vpp
|
||||
client1:
|
||||
kind: linux
|
||||
exec:
|
||||
- ip link set address 00:c1:ab:00:00:01 dev eth1
|
||||
- ip addr add 10.82.98.66/28 dev eth1
|
||||
- ip route add 10.82.98.0/24 via 10.82.98.65
|
||||
- ip addr add 2001:db8:8298:101::2/64 dev eth1
|
||||
- ip route add 2001:db8:8298::/48 via 2001:db8:8298:101::1
|
||||
client2:
|
||||
kind: linux
|
||||
exec:
|
||||
- ip link set address 00:c1:ab:00:00:02 dev eth1
|
||||
- ip addr add 10.82.98.82/28 dev eth1
|
||||
- ip route add 10.82.98.0/24 via 10.82.98.81
|
||||
- ip addr add 2001:db8:8298:102::2/64 dev eth1
|
||||
- ip route add 2001:db8:8298::/48 via 2001:db8:8298:102::1
|
||||
|
||||
links:
|
||||
- endpoints: ["vpp1:eth2", "vpp2:eth2"]
|
||||
- endpoints: ["client1:eth1", "vpp1:eth1"]
|
||||
- endpoints: ["client2:eth1", "vpp2:eth1"]
|
||||
58
tests/02-vpp-frr/01-e2e-lab.robot
Normal file
58
tests/02-vpp-frr/01-e2e-lab.robot
Normal file
@@ -0,0 +1,58 @@
|
||||
*** Settings ***
|
||||
Library OperatingSystem
|
||||
Resource ../ssh.robot
|
||||
Resource ../common.robot
|
||||
|
||||
Suite Teardown Run Keyword Cleanup
|
||||
|
||||
|
||||
*** Variables ***
|
||||
${lab-name} e2e-vpp
|
||||
${lab-file-name} e2e-lab/vpp.clab.yml
|
||||
${runtime} docker
|
||||
|
||||
|
||||
*** Test Cases ***
|
||||
Deploy ${lab-name} lab
|
||||
Log ${CURDIR}
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} deploy -t ${CURDIR}/${lab-file-name}
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
|
||||
Pause to let OSPF converge
|
||||
Sleep 20s
|
||||
|
||||
Check BFD Adjacencies
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file-name} --label clab-node-name\=vpp1 --cmd "vtysh -c 'show bfd peers brief'"
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
Should Match Regexp ${output} (?m)10\.82\.98\..*10\.82\.98\..*up
|
||||
Should Match Regexp ${output} (?m)fe80::.*fe80::.*up
|
||||
|
||||
Check OSPF IPv4 Adjacency
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file-name} --label clab-node-name\=vpp1 --cmd "vtysh -c 'show ip ospf nei'"
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
Should Match Regexp ${output} (?m)Full/.*eth2
|
||||
|
||||
Check OSPF IPv6 Adjacency
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file-name} --label clab-node-name\=vpp2 --cmd "vtysh -c 'show ipv6 ospf nei'"
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
Should Match Regexp ${output} (?m)Full/.*eth2
|
||||
|
||||
Ensure client1 can ping client2
|
||||
${rc} ${output} = Run And Return Rc And Output
|
||||
... ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file-name} --label clab-node-name\=client1 --cmd "ping -c 5 10.82.98.82"
|
||||
Log ${output}
|
||||
Should Be Equal As Integers ${rc} 0
|
||||
Should Contain ${output} 5 packets transmitted, 4 packets received, 20% packet loss
|
||||
|
||||
|
||||
*** Keywords ***
|
||||
Cleanup
|
||||
Run ${CLAB_BIN} --runtime ${runtime} destroy -t ${CURDIR}/${lab-file-name} --cleanup
|
||||
31
tests/02-vpp-frr/e2e-lab/config/vpp1/frr.conf
Normal file
31
tests/02-vpp-frr/e2e-lab/config/vpp1/frr.conf
Normal file
@@ -0,0 +1,31 @@
|
||||
frr version 10.3
|
||||
frr defaults traditional
|
||||
hostname vpp1
|
||||
log syslog informational
|
||||
service integrated-vtysh-config
|
||||
!
|
||||
ip router-id 10.82.98.0
|
||||
!
|
||||
interface eth2
|
||||
ip ospf area 0
|
||||
ip ospf bfd
|
||||
ip ospf cost 10
|
||||
ip ospf network point-to-point
|
||||
ipv6 ospf6 area 0
|
||||
ipv6 ospf6 bfd
|
||||
ipv6 ospf6 cost 10
|
||||
ipv6 ospf6 network point-to-point
|
||||
exit
|
||||
!
|
||||
interface loop0
|
||||
ip ospf passive
|
||||
exit
|
||||
!
|
||||
router ospf
|
||||
redistribute connected
|
||||
exit
|
||||
!
|
||||
router ospf6
|
||||
redistribute connected
|
||||
exit
|
||||
!
|
||||
16
tests/02-vpp-frr/e2e-lab/config/vpp1/vppcfg.yaml
Normal file
16
tests/02-vpp-frr/e2e-lab/config/vpp1/vppcfg.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
interfaces:
|
||||
eth1:
|
||||
description: "To client1"
|
||||
mtu: 1500
|
||||
lcp: eth1
|
||||
addresses: [10.82.98.65/28, 2001:db8:8298:101::1/64]
|
||||
eth2:
|
||||
description: "To vpp2"
|
||||
mtu: 9216
|
||||
lcp: eth2
|
||||
addresses: [10.82.98.16/31, 2001:db8:8298:1::1/64]
|
||||
loopbacks:
|
||||
loop0:
|
||||
description: "vpp1"
|
||||
lcp: loop0
|
||||
addresses: [10.82.98.0/32, 2001:db8:8298::/128]
|
||||
31
tests/02-vpp-frr/e2e-lab/config/vpp2/frr.conf
Normal file
31
tests/02-vpp-frr/e2e-lab/config/vpp2/frr.conf
Normal file
@@ -0,0 +1,31 @@
|
||||
frr version 10.3
|
||||
frr defaults traditional
|
||||
hostname vpp2
|
||||
log syslog informational
|
||||
service integrated-vtysh-config
|
||||
!
|
||||
ip router-id 10.82.98.1
|
||||
!
|
||||
interface eth2
|
||||
ip ospf area 0
|
||||
ip ospf bfd
|
||||
ip ospf cost 10
|
||||
ip ospf network point-to-point
|
||||
ipv6 ospf6 area 0
|
||||
ipv6 ospf6 bfd
|
||||
ipv6 ospf6 cost 10
|
||||
ipv6 ospf6 network point-to-point
|
||||
exit
|
||||
!
|
||||
interface loop0
|
||||
ip ospf passive
|
||||
exit
|
||||
!
|
||||
router ospf
|
||||
redistribute connected
|
||||
exit
|
||||
!
|
||||
router ospf6
|
||||
redistribute connected
|
||||
exit
|
||||
!
|
||||
16
tests/02-vpp-frr/e2e-lab/config/vpp2/vppcfg.yaml
Normal file
16
tests/02-vpp-frr/e2e-lab/config/vpp2/vppcfg.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
interfaces:
|
||||
eth1:
|
||||
description: "To client2"
|
||||
mtu: 1500
|
||||
lcp: eth1
|
||||
addresses: [10.82.98.81/28, 2001:db8:8298:102::1/64]
|
||||
eth2:
|
||||
description: "To vpp1"
|
||||
mtu: 9216
|
||||
lcp: eth2
|
||||
addresses: [10.82.98.17/31, 2001:db8:8298:1::2/64]
|
||||
loopbacks:
|
||||
loop0:
|
||||
description: "vpp2"
|
||||
lcp: loop0
|
||||
addresses: [10.82.98.1/32, 2001:db8:8298::1/128]
|
||||
41
tests/02-vpp-frr/e2e-lab/vpp.clab.yml
Normal file
41
tests/02-vpp-frr/e2e-lab/vpp.clab.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
name: e2e-vpp
|
||||
|
||||
topology:
|
||||
kinds:
|
||||
fdio_vpp:
|
||||
image: ${IMAGE}
|
||||
startup-config: config/__clabNodeName__/vppcfg.yaml
|
||||
binds:
|
||||
- config/__clabNodeName__/frr.conf:/config/frr/frr.conf:ro
|
||||
env:
|
||||
BIRD_ENABLED: false
|
||||
FRR_ENABLED: true
|
||||
linux:
|
||||
image: alpine:latest
|
||||
|
||||
nodes:
|
||||
vpp1:
|
||||
kind: fdio_vpp
|
||||
vpp2:
|
||||
kind: fdio_vpp
|
||||
client1:
|
||||
kind: linux
|
||||
exec:
|
||||
- ip link set address 00:c1:ab:00:00:01 dev eth1
|
||||
- ip addr add 10.82.98.66/28 dev eth1
|
||||
- ip route add 10.82.98.0/24 via 10.82.98.65
|
||||
- ip addr add 2001:db8:8298:101::2/64 dev eth1
|
||||
- ip route add 2001:db8:8298::/48 via 2001:db8:8298:101::1
|
||||
client2:
|
||||
kind: linux
|
||||
exec:
|
||||
- ip link set address 00:c1:ab:00:00:02 dev eth1
|
||||
- ip addr add 10.82.98.82/28 dev eth1
|
||||
- ip route add 10.82.98.0/24 via 10.82.98.81
|
||||
- ip addr add 2001:db8:8298:102::2/64 dev eth1
|
||||
- ip route add 2001:db8:8298::/48 via 2001:db8:8298:102::1
|
||||
|
||||
links:
|
||||
- endpoints: ["vpp1:eth2", "vpp2:eth2"]
|
||||
- endpoints: ["client1:eth1", "vpp1:eth1"]
|
||||
- endpoints: ["client2:eth1", "vpp2:eth1"]
|
||||
2
tests/common.robot
Normal file
2
tests/common.robot
Normal file
@@ -0,0 +1,2 @@
|
||||
*** Variables ***
|
||||
${CLAB_BIN} containerlab
|
||||
2
tests/requirements.txt
Normal file
2
tests/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
robotframework
|
||||
robotframework-sshlibrary
|
||||
45
tests/rf-run.sh
Executable file
45
tests/rf-run.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
# Run Robot Framework tests for vpp-containerlab.
|
||||
# Arguments:
|
||||
# $1 - container runtime: [docker, podman]
|
||||
# $2 - test suite path (directory or .robot file)
|
||||
#
|
||||
# Environment variables:
|
||||
# CLAB_BIN - path to containerlab binary (default: containerlab)
|
||||
# IMAGE - docker image to use in topology (must be set)
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "${CLAB_BIN}" ]; then
|
||||
CLAB_BIN=containerlab
|
||||
fi
|
||||
|
||||
if [ -z "${IMAGE}" ]; then
|
||||
echo "ERROR: IMAGE environment variable must be set" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
mkdir -p "${SCRIPT_DIR}/out"
|
||||
|
||||
source "${SCRIPT_DIR}/.venv/bin/activate"
|
||||
|
||||
function get_logname() {
|
||||
path=$1
|
||||
filename=$(basename "$path")
|
||||
if [[ "$filename" == *.* ]]; then
|
||||
dirname=$(dirname "$path")
|
||||
basename=$(basename "$path" | cut -d. -f1)
|
||||
echo "${dirname##*/}-${basename}"
|
||||
else
|
||||
echo "${filename}"
|
||||
fi
|
||||
}
|
||||
|
||||
robot --consolecolors on -r none \
|
||||
--variable CLAB_BIN:"${CLAB_BIN}" \
|
||||
--variable runtime:"$1" \
|
||||
-l "${SCRIPT_DIR}/out/$(get_logname $2)-$1-log" \
|
||||
--output "${SCRIPT_DIR}/out/$(get_logname $2)-$1-out.xml" \
|
||||
"$2"
|
||||
44
tests/ssh.robot
Normal file
44
tests/ssh.robot
Normal file
@@ -0,0 +1,44 @@
|
||||
*** Settings ***
|
||||
Library SSHLibrary
|
||||
|
||||
|
||||
*** Keywords ***
|
||||
Login via SSH with username and password
|
||||
[Arguments]
|
||||
... ${address}=${None}
|
||||
... ${port}=22
|
||||
... ${username}=${None}
|
||||
... ${password}=${None}
|
||||
# seconds to try and successfully login
|
||||
... ${try_for}=4
|
||||
... ${conn_timeout}=3
|
||||
FOR ${i} IN RANGE ${try_for}
|
||||
SSHLibrary.Open Connection ${address} timeout=${conn_timeout}
|
||||
${status}= Run Keyword And Return Status SSHLibrary.Login ${username} ${password}
|
||||
IF ${status} BREAK
|
||||
Sleep 1s
|
||||
END
|
||||
IF $status!=True
|
||||
Fail Unable to connect to ${address} via SSH in ${try_for} attempts
|
||||
END
|
||||
Log Exited the loop.
|
||||
|
||||
Login via SSH with public key
|
||||
[Arguments]
|
||||
... ${address}=${None}
|
||||
... ${port}=22
|
||||
... ${username}=${None}
|
||||
... ${keyfile}=${None}
|
||||
... ${try_for}=4
|
||||
... ${conn_timeout}=3
|
||||
FOR ${i} IN RANGE ${try_for}
|
||||
SSHLibrary.Open Connection ${address} timeout=${conn_timeout}
|
||||
${status}= Run Keyword And Return Status SSHLibrary.Login With Public Key
|
||||
... ${username} ${keyfile}
|
||||
IF ${status} BREAK
|
||||
Sleep 1s
|
||||
END
|
||||
IF $status!=True
|
||||
Fail Unable to connect to ${address} via SSH in ${try_for} attempts
|
||||
END
|
||||
Log Exited the loop.
|
||||
Reference in New Issue
Block a user