| name | eve-ng-emulator |
| description | Automate EVE-NG network emulation lab creation, management, and topology deployment using evengsdk Python library and CLI. Use when you need to (1) Create or manage EVE-NG virtual network labs programmatically, (2) Deploy network topologies from YAML definitions, (3) Configure virtual network devices with templates or files, (4) Build automated test environments for network validation, (5) Manage nodes, networks, and links in EVE-NG labs, (6) Integrate network lab provisioning into CI/CD pipelines |
| license | Apache-2.0 |
| metadata | {"author":"eve-ng-skill","version":"1.0","requires":"evengsdk, Python 3.8+, EVE-NG instance"} |
EVE-NG Emulator Skill
Overview
EVE-NG (Emulated Virtual Environment - Next Generation) is a powerful network emulation platform that allows you to create virtual network labs with routers, switches, firewalls, and other network devices. This skill enables you to programmatically manage EVE-NG labs using the evengsdk Python library and CLI tools.
What this skill provides:
- Automated lab creation and management
- Programmatic topology deployment
- Device configuration automation
- Integration with network automation workflows
- YAML-based declarative topology definitions
Prerequisites:
- EVE-NG instance (Community or Professional edition)
- Python 3.8 or higher
- Network access to EVE-NG API
- Valid EVE-NG credentials
When to Use This Skill
Use this skill when you need to:
- Automated Testing: Create reproducible network labs for testing automation scripts
- CI/CD Integration: Deploy test topologies as part of continuous integration pipelines
- Training Labs: Quickly provision training environments with consistent configurations
- Network Design Validation: Test network designs before physical deployment
- Rapid Prototyping: Experiment with network architectures and protocols
- Documentation: Generate lab topologies from infrastructure-as-code definitions
Installation & Setup
Install evengsdk
pip install eve-ng
eve-ng --help
Configure Environment Variables
Create a .env file or export variables:
export EVE_NG_HOST=192.168.1.100
export EVE_NG_USERNAME=admin
export EVE_NG_PASSWORD=eve
export EVE_NG_PORT=80
export EVE_NG_PROTOCOL=http
export EVE_NG_SSL_VERIFY=False
export EVE_NG_LAB_PATH='/mylab.unl'
Test Connectivity
from evengsdk.client import EvengClient
client = EvengClient("192.168.1.100", log_file="eve.log", ssl_verify=False)
client.disable_insecure_warnings()
client.login(username="admin", password="eve")
templates = client.api.list_node_templates()
print(f"Available templates: {len(templates['data'])}")
client.logout()
Core Concepts
Labs
- Container for network topology
- Path: Directory-like structure (e.g.,
/, /projects/)
- File format:
.unl extension
- Contains nodes, networks, and links
Nodes
- Virtual devices: Routers, switches, firewalls, servers
- Templates: Pre-configured device types (vEOS, CSR1000v, vIOS, etc.)
- Properties: Name, template, image, position, configuration
- States: Stopped, started, configured
Networks
- Connection points for nodes
- Types:
pnet0-9: Bridge to physical networks (management)
bridge: Internal network segments
- Visibility: Controls display in topology
Links
- Connections between nodes or nodes-to-networks
- Types:
- Node-to-cloud: Management connections
- Node-to-node: Point-to-point links
- Labels: Interface names (e.g.,
Gi0/0, Eth1)
Templates
- Device definitions available in EVE-NG
- Examples:
veos, viosl2, csr1000v, nxosv9k
- Images: Specific versions (e.g.,
veos-4.22.0F)
Basic Operations
1. Lab Management
Create a Lab
from evengsdk.client import EvengClient
client = EvengClient("192.168.1.100", ssl_verify=False)
client.login(username="admin", password="eve")
lab = {
"name": "my_network_lab",
"description": "Test Lab for Automation",
"path": "/"
}
response = client.api.create_lab(**lab)
if response['status'] == "success":
print(f"Lab created: {lab['name']}")
lab_path = f"{lab['path']}{lab['name']}.unl"
else:
print(f"Error: {response.get('message')}")
client.logout()
List Labs
labs = client.api.list_labs()
for lab in labs['data']:
print(f"Lab: {lab['name']} - Path: {lab['path']}")
Delete a Lab
lab_path = "/my_network_lab.unl"
response = client.api.delete_lab(lab_path)
2. Node Management
Add Nodes to Lab
lab_path = "/my_network_lab.unl"
nodes = [
{
"name": "spine01",
"template": "veos",
"image": "veos-4.22.0F",
"left": 100,
"top": 100
},
{
"name": "leaf01",
"template": "veos",
"image": "veos-4.22.0F",
"left": 50,
"top": 300
},
{
"name": "leaf02",
"template": "veos",
"image": "veos-4.22.0F",
"left": 200,
"top": 300
}
]
for node in nodes:
response = client.api.add_node(lab_path, **node)
print(f"Added node: {node['name']}")
List Available Templates
templates = client.api.list_node_templates()
for template_name, template_desc in templates['data'].items():
print(f"{template_name}: {template_desc}")
Start/Stop Nodes
client.api.start_all_nodes(lab_path)
client.api.stop_all_nodes(lab_path)
node_id = 1
client.api.start_node(lab_path, node_id)
3. Network Management
Create Management Network
lab_path = "/my_network_lab.unl"
mgmt_cloud = {
"name": "mgmt-network",
"network_type": "pnet1",
"visibility": 1
}
response = client.api.add_lab_network(lab_path, **mgmt_cloud)
print(f"Created network: {mgmt_cloud['name']}")
Create Internal Networks
internal_net = {
"name": "internal-net",
"network_type": "bridge",
"visibility": 1
}
client.api.add_lab_network(lab_path, **internal_net)
4. Link Management
Connect Nodes to Management Network
lab_path = "/my_network_lab.unl"
mgmt_connections = [
{"src": "spine01", "src_label": "Management1", "dst": "mgmt-network"},
{"src": "leaf01", "src_label": "Management1", "dst": "mgmt-network"},
{"src": "leaf02", "src_label": "Management1", "dst": "mgmt-network"}
]
for link in mgmt_connections:
client.api.connect_node_to_cloud(lab_path, **link)
print(f"Connected {link['src']} to {link['dst']}")
Create Point-to-Point Links
p2p_links = [
{"src": "spine01", "src_label": "Ethernet1", "dst": "leaf01", "dst_label": "Ethernet1"},
{"src": "spine01", "src_label": "Ethernet2", "dst": "leaf02", "dst_label": "Ethernet1"}
]
for link in p2p_links:
client.api.connect_node_to_node(lab_path, **link)
print(f"Connected {link['src']}:{link['src_label']} to {link['dst']}:{link['dst_label']}")
5. Configuration Deployment
Using Configuration Files
node_config = {
"name": "leaf01",
"config_file": "/path/to/configs/leaf01.cfg"
}
Using Jinja2 Templates
node_with_template = {
"name": "leaf02",
"template": "veos",
"image": "veos-4.22.0F",
"configuration": {
"template": "base.j2",
"vars": {
"hostname": "leaf02",
"management_ip": "10.0.0.2/24",
"gateway": "10.0.0.1"
}
}
}
Example Jinja2 Template (base.j2):
hostname {{ hostname }}
!
interface Management1
ip address {{ management_ip }}
no shutdown
!
ip route 0.0.0.0/0 {{ gateway }}
Topology Builder (YAML-based)
The topology builder allows you to define entire labs declaratively using YAML files.
YAML Topology Format
---
name: leaf-spine-lab
description: 2-Spine 4-Leaf Topology
path: "/"
nodes:
- name: spine01
template: veos
image: veos-4.22.0F
node_type: qemu
left: 200
top: 100
configuration:
template: spine.j2
vars:
hostname: spine01
router_id: 1.1.1.1
asn: 65001
- name: spine02
template: veos
image: veos-4.22.0F
node_type: qemu
left: 400
top: 100
configuration:
template: spine.j2
vars:
hostname: spine02
router_id: 1.1.1.2
asn: 65001
- name: leaf01
template: veos
image: veos-4.22.0F
node_type: qemu
left: 100
top: 300
configuration:
file: configs/leaf01.cfg
- name: leaf02
template: veos
image: veos-4.22.0F
node_type: qemu
left: 250
top: 300
networks:
- name: mgmt-cloud
network_type: pnet1
visibility: 1
top: 50
left: 500
links:
network:
- {src: "spine01", src_label: "Management1", dst: "mgmt-cloud"}
- {src: "spine02", src_label: "Management1", dst: "mgmt-cloud"}
- {src: "leaf01", src_label: "Management1", dst: "mgmt-cloud"}
- {src: "leaf02", src_label: "Management1", dst: "mgmt-cloud"}
node:
- {src: "spine01", src_label: "Ethernet1", dst: "leaf01", dst_label: "Ethernet1"}
- {src: "spine01", src_label: "Ethernet2", dst: "leaf02", dst_label: "Ethernet1"}
- {src: "spine02", src_label: "Ethernet1", dst: "leaf01", dst_label: "Ethernet2"}
- {src: "spine02", src_label: "Ethernet2", dst: "leaf02", dst_label: "Ethernet2"}
Deploy Topology from YAML
eve-ng lab create-from-topology \
-t topologies/leaf-spine-lab.yml \
--template-dir templates/
from evengsdk.topology import TopologyBuilder
builder = TopologyBuilder(client)
builder.build_from_yaml("topologies/leaf-spine-lab.yml", template_dir="templates/")
CLI Usage Examples
Lab Commands
eve-ng --host $EVE_NG_HOST --username $EVE_NG_USERNAME --password $EVE_NG_PASSWORD lab list
eve-ng lab create --name test-lab --path /
eve-ng lab delete --path /test-lab.unl
eve-ng lab show --path /test-lab.unl
Node Commands
eve-ng node list --lab-path /test-lab.unl
eve-ng node add \
--lab-path /test-lab.unl \
--name router01 \
--template vios \
--image vios-15.6
eve-ng node start-all --lab-path /test-lab.unl
eve-ng node stop --lab-path /test-lab.unl --node-id 1
System Commands
eve-ng list-node-templates
eve-ng list-network-types
eve-ng show-status
eve-ng show-template --template veos
Complete Example: Leaf-Spine Topology
from evengsdk.client import EvengClient
def create_leaf_spine_lab():
client = EvengClient("192.168.1.100", ssl_verify=False, protocol="http")
client.disable_insecure_warnings()
client.login(username="admin", password="eve")
client.set_log_level("INFO")
lab = {
"name": "leaf_spine_lab",
"description": "2-Spine 4-Leaf EVPN/VXLAN Lab",
"path": "/"
}
resp = client.api.create_lab(**lab)
if resp['status'] != "success":
print(f"Error creating lab: {resp}")
return
lab_path = f"{lab['path']}{lab['name']}.unl"
print(f"Created lab: {lab_path}")
mgmt_cloud = {"name": "mgmt", "network_type": "pnet1"}
client.api.add_lab_network(lab_path, **mgmt_cloud)
print("Created management network")
spines = [
{"name": "spine01", "template": "veos", "image": "veos-4.22.0F", "left": 200, "top": 100},
{"name": "spine02", "template": "veos", "image": "veos-4.22.0F", "left": 400, "top": 100}
]
leaves = [
{"name": "leaf01", "template": "veos", "image": "veos-4.22.0F", "left": 100, "top": 300},
{"name": "leaf02", "template": "veos", "image": "veos-4.22.0F", "left": 250, "top": 300},
{"name": "leaf03", "template": "veos", "image": "veos-4.22.0F", "left": 400, "top": 300},
{"name": "leaf04", "template": "veos", "image": "veos-4.22.0F", "left": 550, "top": 300}
]
all_nodes = spines + leaves
for node in all_nodes:
client.api.add_node(lab_path, **node)
print(f"Added node: {node['name']}")
for node in all_nodes:
link = {"src": node['name'], "src_label": "Management1", "dst": "mgmt"}
client.api.connect_node_to_cloud(lab_path, **link)
print("Connected all nodes to management network")
for spine in spines:
for idx, leaf in enumerate(leaves, start=1):
link = {
"src": spine['name'],
"src_label": f"Ethernet{idx}",
"dst": leaf['name'],
"dst_label": f"Ethernet{spines.index(spine) + 1}"
}
client.api.connect_node_to_node(lab_path, **link)
print(f"Connected {link['src']}:{link['src_label']} to {link['dst']}:{link['dst_label']}")
print("\n✅ Lab creation complete!")
print(f"Lab path: {lab_path}")
print(f"Total nodes: {len(all_nodes)}")
client.logout()
if __name__ == "__main__":
create_leaf_spine_lab()
Common Patterns
Hub-and-Spoke Topology
def create_hub_spoke(client, lab_path):
hub = {"name": "hub-router", "template": "vios", "image": "vios-15.6", "left": 300, "top": 200}
client.api.add_node(lab_path, **hub)
spokes = [
{"name": f"spoke{i}", "template": "vios", "image": "vios-15.6",
"left": 100 + (i * 150), "top": 400}
for i in range(1, 5)
]
for spoke in spokes:
client.api.add_node(lab_path, **spoke)
link = {
"src": "hub-router",
"src_label": f"GigabitEthernet0/{spokes.index(spoke)}",
"dst": spoke['name'],
"dst_label": "GigabitEthernet0/0"
}
client.api.connect_node_to_node(lab_path, **link)
Full Mesh Topology
def create_full_mesh(client, lab_path, nodes):
for node in nodes:
client.api.add_node(lab_path, **node)
interface_counter = {}
for i, node1 in enumerate(nodes):
interface_counter[node1['name']] = 0
for node2 in nodes[i+1:]:
link = {
"src": node1['name'],
"src_label": f"Ethernet{interface_counter[node1['name']]}",
"dst": node2['name'],
"dst_label": f"Ethernet{interface_counter.get(node2['name'], 0)}"
}
client.api.connect_node_to_node(lab_path, **link)
interface_counter[node1['name']] += 1
interface_counter[node2['name']] = interface_counter.get(node2['name'], 0) + 1
Troubleshooting
Connection Issues
Problem: Cannot connect to EVE-NG API
Solutions:
import requests
response = requests.get("http://192.168.1.100/api/status")
print(response.status_code)
client = EvengClient("192.168.1.100")
try:
client.login(username="admin", password="eve")
print("✅ Login successful")
except Exception as e:
print(f"❌ Login failed: {e}")
Template Not Found
Problem: Error adding node - template not available
Solution:
templates = client.api.list_node_templates()
available = [t for t in templates['data'].keys() if 'missing' not in templates['data'][t]]
print(f"Available templates: {available}")
template_name = "veos"
if template_name in available:
print(f"✅ Template {template_name} is available")
else:
print(f"❌ Template {template_name} not found")
Node Startup Failures
Problem: Nodes fail to start
Checks:
- Verify image is uploaded to EVE-NG
- Check EVE-NG server resources (CPU, RAM)
- Review node console for errors
- Verify template configuration
eve-ng show-status
eve-ng node show --lab-path /test-lab.unl --node-id 1
Authentication Errors
Problem: 401 Unauthorized errors
Solutions:
client.login(username="admin", password="eve")
import os
username = os.getenv("EVE_NG_USERNAME")
password = os.getenv("EVE_NG_PASSWORD")
Best Practices
Lab Organization
- Use descriptive names:
leaf-spine-evpn not lab1
- Organize by path: Group related labs in folders
- Version control: Store YAML topologies in git
- Document purpose: Use clear descriptions
Naming Conventions
nodes = [
{"name": "core-router-01", ...},
{"name": "access-switch-floor2", ...},
{"name": "fw-dmz-primary", ...}
]
nodes = [
{"name": "router1", ...},
{"name": "switch", ...},
{"name": "device", ...}
]
Resource Management
client.api.stop_all_nodes(lab_path)
client.api.delete_lab("/old-lab.unl")
status = client.api.get_server_status()
print(f"CPU: {status['cpu']}%, RAM: {status['ram']}%")
Configuration Management
- Use templates: Jinja2 for dynamic configs
- Separate data: Keep variables in separate files
- Version control: Track configuration changes
- Validate configs: Test before deployment
config = {
"template": "base.j2",
"vars": "data/leaf01.yml"
}
config = {
"file": "configs/v2.0/leaf01.cfg"
}
Error Handling
def safe_lab_creation(client, lab_config):
try:
response = client.api.create_lab(**lab_config)
if response['status'] == 'success':
return response
else:
print(f"Lab creation failed: {response.get('message')}")
return None
except Exception as e:
print(f"Error: {e}")
return None
Limitations & Gotchas
EVE-NG Version Compatibility
- evengsdk works with EVE-NG Community and Professional
- API endpoints may vary between versions
- Always test with your specific EVE-NG version
Resource Constraints
- Each node consumes CPU and RAM
- Monitor server resources before adding many nodes
- Consider node startup time in automation
Template Availability
- Templates must be installed on EVE-NG server
- Image files must be uploaded separately
- Template names are case-sensitive
Network Type Restrictions
pnet0-9: Limited to 10 physical network bridges
- Network types depend on EVE-NG configuration
- Some network types require specific permissions
API Rate Limiting
- Avoid rapid API calls in loops
- Use batch operations when possible
- Implement retry logic for transient failures
Configuration Deployment
- Configurations apply on node startup
- Changes require node restart to take effect
- Template rendering happens server-side
Integration Examples
CI/CD Pipeline Integration
test-network-automation:
stage: test
script:
- pip install eve-ng ansible
- eve-ng lab create-from-topology -t test-topology.yml
- ansible-playbook -i eve-inventory.yml test-playbook.yml
- eve-ng lab delete --path /test-topology.unl
only:
- merge_requests
Ansible Integration
---
- name: Deploy EVE-NG Lab
hosts: localhost
tasks:
- name: Create lab from topology
command: >
eve-ng lab create-from-topology
-t {{ topology_file }}
--template-dir {{ template_dir }}
environment:
EVE_NG_HOST: "{{ eve_host }}"
EVE_NG_USERNAME: "{{ eve_user }}"
EVE_NG_PASSWORD: "{{ eve_pass }}"
Python Automation Framework
class EVELabManager:
def __init__(self, host, username, password):
self.client = EvengClient(host, ssl_verify=False)
self.client.login(username=username, password=password)
def deploy_topology(self, yaml_file):
"""Deploy topology from YAML file"""
pass
def validate_connectivity(self, lab_path):
"""Validate all nodes are connected"""
pass
def cleanup(self, lab_path):
"""Stop and delete lab"""
self.client.api.stop_all_nodes(lab_path)
self.client.api.delete_lab(lab_path)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.client.logout()
with EVELabManager("192.168.1.100", "admin", "eve") as manager:
manager.deploy_topology("topology.yml")
manager.validate_connectivity("/topology.unl")
Additional Resources
Quick Reference
Common Commands
eve-ng lab list
eve-ng lab create --name <name> --path <path>
eve-ng lab delete --path <lab_path>
eve-ng node list --lab-path <lab_path>
eve-ng node start-all --lab-path <lab_path>
eve-ng node stop-all --lab-path <lab_path>
eve-ng list-node-templates
eve-ng show-status
Python Quick Start
from evengsdk.client import EvengClient
client = EvengClient("host", ssl_verify=False)
client.login(username="admin", password="eve")
client.api.create_lab(name="lab", description="desc", path="/")
client.api.add_node("/lab.unl", name="r1", template="vios", image="vios-15.6")
client.api.connect_node_to_node("/lab.unl", src="r1", src_label="Gi0/0",
dst="r2", dst_label="Gi0/0")
client.logout()