Add network schema for devices, interfaces, VLANs, VRFs, BGP configurations, MLAG, EVPN, VXLAN, routing policies, and DCI connections
- Created device schema with attributes for hostname, role, platform, and management IP. - Added interface schema with various types, MTU, speed, and switchport modes. - Introduced VLAN and VRF schemas with relationships to devices and interfaces. - Implemented BGP configuration, peer groups, and neighbors with detailed attributes. - Established MLAG domain and interface schemas for multi-chassis link aggregation. - Developed EVPN and VXLAN schemas for overlay networking. - Created routing policy schemas including route maps and prefix lists. - Added DCI switch and connection schemas for inter-datacenter connectivity.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
containerlab/cEOS64-lab-4.35.0F.tar.xz
|
containerlab/cEOS64-lab-4.35.0F.tar.xz
|
||||||
containerlab/clab-arista-l5-dual-dc
|
containerlab/clab-arista-l5-dual-dc
|
||||||
|
.envrc
|
||||||
|
|||||||
2
envrc.sample
Normal file
2
envrc.sample
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export INFRAHUB_ADDRESS="https://infrahub.mylab.net"
|
||||||
|
export INFRAHUB_API_TOKEN="tata-34da-toto-35db-test"
|
||||||
604
infrahub/design.md
Normal file
604
infrahub/design.md
Normal file
@@ -0,0 +1,604 @@
|
|||||||
|
# Data Center Design Philosophy & Automation Model
|
||||||
|
|
||||||
|
## 🎯 Core Concept: Datacenter as a Generator
|
||||||
|
|
||||||
|
### The Vision
|
||||||
|
A **Datacenter** is a **generator object** in Infrahub that creates all child objects automatically based on parent attributes and business logic.
|
||||||
|
|
||||||
|
```
|
||||||
|
Input: Datacenter Object (with attributes)
|
||||||
|
↓
|
||||||
|
Business Logic (naming conventions, network design patterns)
|
||||||
|
↓
|
||||||
|
Output: Complete infrastructure (devices, interfaces, IPs, BGP sessions)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Hierarchical Data Model
|
||||||
|
|
||||||
|
### Level 0: Organization (Root)
|
||||||
|
```
|
||||||
|
Organization
|
||||||
|
├── Sites (geographic locations)
|
||||||
|
└── IP Address Space (RFC 1918 allocations)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Level 1: Site (Geographic)
|
||||||
|
```
|
||||||
|
Site
|
||||||
|
├── Name: "Paris-DC1"
|
||||||
|
├── Location: "Paris, France"
|
||||||
|
├── Type: "Production"
|
||||||
|
└── Parent Subnet: 10.0.0.0/8
|
||||||
|
```
|
||||||
|
|
||||||
|
### Level 2: Datacenter (Logical Fabric)
|
||||||
|
```
|
||||||
|
Datacenter
|
||||||
|
├── Site: Paris-DC1
|
||||||
|
├── DC ID: 1 (for IP addressing: 10.1.x.x)
|
||||||
|
├── Number of Bays: 2 (scalable)
|
||||||
|
├── Spine Count: 3 (fixed for now)
|
||||||
|
├── Border Leaf Count: 2 (fixed for now)
|
||||||
|
└── Generates:
|
||||||
|
├── Devices (Spines, Leafs, Border Leafs, Access switches)
|
||||||
|
├── IP Subnets (loopbacks, P2P, MLAG, tenants)
|
||||||
|
├── Interfaces (physical, loopbacks, VLANs)
|
||||||
|
├── BGP Configuration (ASNs, peers)
|
||||||
|
└── MLAG Pairs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Level 3: Bay/Rack (Physical)
|
||||||
|
```
|
||||||
|
Bay
|
||||||
|
├── Bay ID: 1, 2, 3...
|
||||||
|
├── Access Switch: access{bay_id}-DC{dc_id}
|
||||||
|
├── Leaf Pair: Assigned based on bay_id (round-robin)
|
||||||
|
├── Host Count: Variable (1-48 per bay)
|
||||||
|
└── Generates:
|
||||||
|
├── Access Switch device
|
||||||
|
├── Access-to-Leaf connections
|
||||||
|
├── Host connections
|
||||||
|
└── VLAN assignments
|
||||||
|
```
|
||||||
|
|
||||||
|
### Level 4: Devices (Auto-generated)
|
||||||
|
```
|
||||||
|
Device
|
||||||
|
├── Hostname: (from naming convention)
|
||||||
|
├── Role: spine|leaf|borderleaf|access
|
||||||
|
├── Interfaces: (auto-generated based on role)
|
||||||
|
├── IP Addresses: (auto-allocated from parent subnets)
|
||||||
|
├── BGP Config: (auto-generated based on role)
|
||||||
|
└── MLAG Config: (if part of pair)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ Datacenter Generator - Input Attributes
|
||||||
|
|
||||||
|
### Required Attributes
|
||||||
|
```yaml
|
||||||
|
name: "DC1" # Human-readable name
|
||||||
|
dc_id: 1 # Numeric ID (for IP addressing)
|
||||||
|
site: "Paris-DC1" # Parent site reference
|
||||||
|
parent_subnet: "10.0.0.0/8" # Address space allocation
|
||||||
|
number_of_bays: 2 # Initial bay count (scalable)
|
||||||
|
has_border_leafs: true # Include border leafs for DCI capability
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optional Attributes (with defaults)
|
||||||
|
```yaml
|
||||||
|
spine_count: 3 # Default: 3
|
||||||
|
spine_asn: 65100 # Default: 65000 + (dc_id * 100)
|
||||||
|
border_leaf_count: 2 # Default: 2 (0 if has_border_leafs: false)
|
||||||
|
bgp_base_asn: 65000 # Default: 65000
|
||||||
|
mlag_domain_id: "MLAG" # Default: "MLAG"
|
||||||
|
mtu: 9214 # Default: 9214
|
||||||
|
dci_enabled: false # Default: false (configure eth12 as shutdown)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Derived/Computed Attributes (auto-calculated)
|
||||||
|
```yaml
|
||||||
|
# Computed from dc_id
|
||||||
|
loopback0_subnet: "10.{dc_id}.0.0/24"
|
||||||
|
loopback1_subnet: "10.{dc_id}.1.0/24"
|
||||||
|
spine_leaf_p2p_subnet: "10.{dc_id}.10.0/24"
|
||||||
|
leaf_access_p2p_subnet: "10.{dc_id}.20.0/24"
|
||||||
|
mlag_peer_subnet: "10.{dc_id}.255.0/24"
|
||||||
|
|
||||||
|
# Computed from number_of_bays
|
||||||
|
leaf_pair_count: ceil(number_of_bays / 2) # 2 bays per leaf pair
|
||||||
|
total_leaf_count: leaf_pair_count * 2
|
||||||
|
total_access_count: number_of_bays
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 Business Logic Rules
|
||||||
|
|
||||||
|
### 1. Naming Conventions
|
||||||
|
|
||||||
|
#### Spine Switches
|
||||||
|
```
|
||||||
|
Pattern: spine{spine_number}-DC{dc_id}
|
||||||
|
Example: spine1-DC1, spine2-DC1, spine3-DC1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Leaf Switches
|
||||||
|
```
|
||||||
|
Pattern: leaf{leaf_number}-DC{dc_id}
|
||||||
|
Example: leaf1-DC1, leaf2-DC1, leaf3-DC1, leaf4-DC1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Border Leaf Switches
|
||||||
|
```
|
||||||
|
Pattern: borderleaf{number}-DC{dc_id}
|
||||||
|
Example: borderleaf1-DC1, borderleaf2-DC1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Access Switches
|
||||||
|
```
|
||||||
|
Pattern: access{bay_id}-DC{dc_id}
|
||||||
|
Example: access1-DC1, access2-DC1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Hosts
|
||||||
|
```
|
||||||
|
Pattern: host{host_number}-DC{dc_id}
|
||||||
|
Example: host1-DC1, host2-DC1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Bay-to-Leaf Assignment Logic
|
||||||
|
|
||||||
|
**Rule**: Each bay connects to ONE leaf pair (round-robin assignment)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Pseudo-code
|
||||||
|
leaf_pairs = [
|
||||||
|
[leaf1, leaf2], # MLAG Pair 1
|
||||||
|
[leaf3, leaf4], # MLAG Pair 2
|
||||||
|
[leaf5, leaf6], # MLAG Pair 3 (if exists)
|
||||||
|
]
|
||||||
|
|
||||||
|
def assign_bay_to_leaf_pair(bay_id, leaf_pairs):
|
||||||
|
pair_index = (bay_id - 1) // 2 # Integer division
|
||||||
|
return leaf_pairs[pair_index]
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
# bay_id=1 → leaf_pairs[0] → [leaf1, leaf2]
|
||||||
|
# bay_id=2 → leaf_pairs[0] → [leaf1, leaf2]
|
||||||
|
# bay_id=3 → leaf_pairs[1] → [leaf3, leaf4]
|
||||||
|
# bay_id=4 → leaf_pairs[1] → [leaf3, leaf4]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Result**:
|
||||||
|
- Bay 1 & 2 → Leaf Pair 1 (leaf1-2)
|
||||||
|
- Bay 3 & 4 → Leaf Pair 2 (leaf3-4)
|
||||||
|
- Bay 5 & 6 → Leaf Pair 3 (leaf5-6)
|
||||||
|
|
||||||
|
### 3. MLAG Pairing Logic
|
||||||
|
|
||||||
|
**Rule**: Odd-numbered leafs pair with next even-numbered leaf
|
||||||
|
|
||||||
|
```python
|
||||||
|
def create_mlag_pairs(total_leafs):
|
||||||
|
pairs = []
|
||||||
|
for i in range(1, total_leafs + 1, 2):
|
||||||
|
pairs.append([f"leaf{i}", f"leaf{i+1}"])
|
||||||
|
return pairs
|
||||||
|
|
||||||
|
# Example with 4 leafs:
|
||||||
|
# → [[leaf1, leaf2], [leaf3, leaf4]]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Interface Assignment Logic
|
||||||
|
|
||||||
|
#### Spine Interfaces
|
||||||
|
```
|
||||||
|
Role: Connect to all leafs + border leafs
|
||||||
|
Pattern:
|
||||||
|
eth2 → leaf1
|
||||||
|
eth3 → leaf2
|
||||||
|
eth4 → leaf3
|
||||||
|
eth5 → leaf4
|
||||||
|
eth6 → borderleaf1
|
||||||
|
eth7 → borderleaf2
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Leaf Interfaces
|
||||||
|
```
|
||||||
|
Role: Uplinks to spines, MLAG peer, downlinks to access
|
||||||
|
Pattern:
|
||||||
|
eth1-2 → MLAG peer link (to paired leaf)
|
||||||
|
eth3-5 → Uplinks (spine1, spine2, spine3)
|
||||||
|
eth7+ → Downlinks to access switches (2 bays per pair)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Access Interfaces
|
||||||
|
```
|
||||||
|
Role: Uplinks to leaf pair, downlinks to hosts
|
||||||
|
Pattern:
|
||||||
|
eth1-2 → Uplinks (to leaf pair via MLAG)
|
||||||
|
eth10+ → Host connections
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. IP Address Allocation Logic
|
||||||
|
|
||||||
|
#### Management IPs (10.255.0.0/24)
|
||||||
|
```python
|
||||||
|
def allocate_mgmt_ip(device_role, device_number, dc_id):
|
||||||
|
base_octets = {
|
||||||
|
'spine': 10 + (dc_id - 1) * 30, # DC1: 11-13, DC2: 41-43
|
||||||
|
'leaf': 20 + (dc_id - 1) * 30, # DC1: 21-24, DC2: 51-54
|
||||||
|
'borderleaf': 30 + (dc_id - 1) * 30, # DC1: 31-32, DC2: 61-62
|
||||||
|
'access': 70 + (dc_id - 1) * 10, # DC1: 71-72, DC2: 81-82
|
||||||
|
'host': 200 + (dc_id - 1) * 10, # DC1: 201-202, DC2: 211-212
|
||||||
|
}
|
||||||
|
return f"10.255.0.{base_octets[device_role] + device_number - 1}"
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
# spine1, DC1 → 10.255.0.11
|
||||||
|
# leaf1, DC1 → 10.255.0.21
|
||||||
|
# access1, DC2 → 10.255.0.81
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Loopback0 (Router IDs)
|
||||||
|
```python
|
||||||
|
def allocate_loopback0(device_role, device_number, dc_id):
|
||||||
|
role_base = {
|
||||||
|
'spine': 11,
|
||||||
|
'leaf': 21,
|
||||||
|
'borderleaf': 31,
|
||||||
|
}
|
||||||
|
return f"10.{dc_id}.0.{role_base[device_role] + device_number - 1}/32"
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
# spine1, DC1 → 10.1.0.11/32
|
||||||
|
# leaf3, DC1 → 10.1.0.23/32
|
||||||
|
# spine2, DC2 → 10.2.0.12/32
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Loopback1 (VTEP - Shared by MLAG pairs)
|
||||||
|
```python
|
||||||
|
def allocate_loopback1_vtep(leaf_number, dc_id):
|
||||||
|
# Odd and even leafs share same VTEP
|
||||||
|
vtep_base = ((leaf_number - 1) // 2) * 2 + 21
|
||||||
|
return f"10.{dc_id}.1.{vtep_base}/32"
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
# leaf1, DC1 → 10.1.1.21/32 (shared with leaf2)
|
||||||
|
# leaf2, DC1 → 10.1.1.21/32 (shared with leaf1)
|
||||||
|
# leaf3, DC1 → 10.1.1.23/32 (shared with leaf4)
|
||||||
|
# leaf4, DC1 → 10.1.1.23/32 (shared with leaf3)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### P2P Links (Spine-Leaf)
|
||||||
|
```python
|
||||||
|
def allocate_spine_leaf_p2p(spine_num, leaf_num, dc_id):
|
||||||
|
# Each spine gets 6 leafs (including borderleafs)
|
||||||
|
# Each link uses /31 (2 IPs)
|
||||||
|
offset = (spine_num - 1) * 12 + (leaf_num - 1) * 2
|
||||||
|
leaf_ip = f"10.{dc_id}.10.{offset}"
|
||||||
|
spine_ip = f"10.{dc_id}.10.{offset + 1}"
|
||||||
|
return (leaf_ip, spine_ip)
|
||||||
|
|
||||||
|
# Example:
|
||||||
|
# spine1 → leaf1 → (10.1.10.0, 10.1.10.1)
|
||||||
|
# spine1 → leaf2 → (10.1.10.2, 10.1.10.3)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### P2P Links (Leaf-Access)
|
||||||
|
```python
|
||||||
|
def allocate_leaf_access_p2p(access_num, leaf_num, dc_id):
|
||||||
|
# 2 uplinks per access (to MLAG leaf pair)
|
||||||
|
offset = (access_num - 1) * 4 + (leaf_num % 2) * 2
|
||||||
|
access_ip = f"10.{dc_id}.20.{offset}"
|
||||||
|
leaf_ip = f"10.{dc_id}.20.{offset + 1}"
|
||||||
|
return (access_ip, leaf_ip)
|
||||||
|
|
||||||
|
# Example:
|
||||||
|
# access1 → leaf1 → (10.1.20.0, 10.1.20.1)
|
||||||
|
# access1 → leaf2 → (10.1.20.2, 10.1.20.3)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### MLAG Peer Links
|
||||||
|
```python
|
||||||
|
def allocate_mlag_peer_ips(leaf_pair_num, dc_id):
|
||||||
|
# Each pair gets /30 (4 IPs, use 2)
|
||||||
|
offset = (leaf_pair_num - 1) * 4 + 1
|
||||||
|
odd_leaf_ip = f"10.{dc_id}.255.{offset}" # .1, .5, .9
|
||||||
|
even_leaf_ip = f"10.{dc_id}.255.{offset + 1}" # .2, .6, .10
|
||||||
|
return (odd_leaf_ip, even_leaf_ip)
|
||||||
|
|
||||||
|
# Example:
|
||||||
|
# Pair 1 (leaf1-2) → (10.1.255.1, 10.1.255.2)
|
||||||
|
# Pair 2 (leaf3-4) → (10.1.255.5, 10.1.255.6)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. BGP ASN Allocation Logic
|
||||||
|
|
||||||
|
```python
|
||||||
|
def allocate_asn(device_role, pair_number, dc_id, base_asn=65000):
|
||||||
|
if device_role == 'spine':
|
||||||
|
return base_asn + (dc_id * 100)
|
||||||
|
elif device_role == 'leaf':
|
||||||
|
return base_asn + (dc_id * 100) + pair_number
|
||||||
|
elif device_role == 'borderleaf':
|
||||||
|
# Border leafs get ASN +3 from base
|
||||||
|
return base_asn + (dc_id * 100) + 3
|
||||||
|
else:
|
||||||
|
return None # Access switches don't run BGP
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
# DC1 Spines → 65100
|
||||||
|
# DC1 Leaf Pair 1 (leaf1-2) → 65101
|
||||||
|
# DC1 Leaf Pair 2 (leaf3-4) → 65102
|
||||||
|
# DC1 Border Leafs → 65103
|
||||||
|
# DC2 Spines → 65200
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Object Relationships & Dependencies
|
||||||
|
|
||||||
|
### Dependency Graph
|
||||||
|
```
|
||||||
|
Organization
|
||||||
|
└── Site
|
||||||
|
├── IP Space Allocation
|
||||||
|
└── Datacenter (GENERATOR)
|
||||||
|
├── Computes: leaf_pair_count from number_of_bays
|
||||||
|
├── Generates Devices:
|
||||||
|
│ ├── Spines (fixed count)
|
||||||
|
│ ├── Leafs (computed count)
|
||||||
|
│ ├── Border Leafs (fixed count)
|
||||||
|
│ └── Access Switches (= number_of_bays)
|
||||||
|
├── Generates IP Subnets:
|
||||||
|
│ ├── Loopback0 subnet
|
||||||
|
│ ├── Loopback1 subnet
|
||||||
|
│ ├── Spine-Leaf P2P subnet
|
||||||
|
│ ├── Leaf-Access P2P subnet
|
||||||
|
│ └── MLAG Peer subnet
|
||||||
|
├── For Each Device:
|
||||||
|
│ ├── Allocates Management IP
|
||||||
|
│ ├── Allocates Loopback IPs (if spine/leaf)
|
||||||
|
│ ├── Creates Interfaces (based on role)
|
||||||
|
│ ├── Allocates P2P IPs (for each link)
|
||||||
|
│ └── Generates BGP Config (if spine/leaf)
|
||||||
|
└── Creates MLAG Pairs:
|
||||||
|
└── Assigns peer IPs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Object Creation Order (to respect dependencies)
|
||||||
|
```
|
||||||
|
1. Site
|
||||||
|
2. IP Prefixes (parent subnets)
|
||||||
|
3. Datacenter (generator starts here)
|
||||||
|
├── 4. Generate Subnets (children of parent subnet)
|
||||||
|
├── 5. Generate Devices (all roles)
|
||||||
|
├── 6. Generate MLAG Pairs (relationships)
|
||||||
|
├── 7. Generate Interfaces (for each device)
|
||||||
|
├── 8. Allocate IP Addresses (for each interface)
|
||||||
|
├── 9. Generate BGP ASNs
|
||||||
|
└── 10. Generate BGP Sessions (relationships)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Scaling Operations
|
||||||
|
|
||||||
|
### Adding a New Bay
|
||||||
|
|
||||||
|
**Input**:
|
||||||
|
- Datacenter: DC1
|
||||||
|
- New bay_id: 3
|
||||||
|
|
||||||
|
**Generator Actions**:
|
||||||
|
1. Create new access switch: `access3-DC1`
|
||||||
|
2. Determine leaf pair assignment:
|
||||||
|
- bay_id=3 → pair_index = (3-1)//2 = 1 → Leaf Pair 2 (leaf3-4)
|
||||||
|
3. Create interfaces:
|
||||||
|
- access3-DC1: eth1, eth2 (uplinks)
|
||||||
|
- leaf3-DC1: add port for access3
|
||||||
|
- leaf4-DC1: add port for access3
|
||||||
|
4. Allocate IPs:
|
||||||
|
- Management: 10.255.0.73
|
||||||
|
- P2P to leaf3: (10.1.20.8, 10.1.20.9)
|
||||||
|
- P2P to leaf4: (10.1.20.10, 10.1.20.11)
|
||||||
|
5. Update datacenter: `number_of_bays: 3`
|
||||||
|
|
||||||
|
**Result**: New bay operational with zero manual config!
|
||||||
|
|
||||||
|
### Adding a New Leaf Pair
|
||||||
|
|
||||||
|
**Trigger**: `number_of_bays > (leaf_pair_count * 2)`
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
- Current: 2 leaf pairs support 4 bays
|
||||||
|
- Request: bay_id = 5
|
||||||
|
- Action: Generate leaf5-DC1 and leaf6-DC1
|
||||||
|
|
||||||
|
**Generator Actions**:
|
||||||
|
1. Create devices: leaf5-DC1, leaf6-DC1
|
||||||
|
2. Create MLAG pair: [leaf5, leaf6]
|
||||||
|
3. Allocate IPs:
|
||||||
|
- Loopback0: 10.1.0.25, 10.1.0.26
|
||||||
|
- Loopback1: 10.1.1.25 (shared)
|
||||||
|
- MLAG Peer: 10.1.255.13, 10.1.255.14
|
||||||
|
4. Create spine uplinks (3 per leaf)
|
||||||
|
5. Allocate BGP ASN: 65104
|
||||||
|
6. Generate BGP config
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Validation Rules
|
||||||
|
|
||||||
|
### Pre-Generation Checks
|
||||||
|
```python
|
||||||
|
def validate_datacenter_input(dc):
|
||||||
|
checks = []
|
||||||
|
|
||||||
|
# Check 1: DC ID must be unique
|
||||||
|
if dc.dc_id in existing_dc_ids:
|
||||||
|
checks.append("ERROR: DC ID already exists")
|
||||||
|
|
||||||
|
# Check 2: Parent subnet must be large enough
|
||||||
|
required_size = calculate_ip_requirements(dc.number_of_bays)
|
||||||
|
if dc.parent_subnet.size < required_size:
|
||||||
|
checks.append("ERROR: Parent subnet too small")
|
||||||
|
|
||||||
|
# Check 3: Number of bays must be positive
|
||||||
|
if dc.number_of_bays < 1:
|
||||||
|
checks.append("ERROR: Must have at least 1 bay")
|
||||||
|
|
||||||
|
# Check 4: ASN must not conflict
|
||||||
|
if asn_conflicts_exist(dc):
|
||||||
|
checks.append("ERROR: ASN conflicts detected")
|
||||||
|
|
||||||
|
return checks
|
||||||
|
```
|
||||||
|
|
||||||
|
### Post-Generation Checks
|
||||||
|
```python
|
||||||
|
def validate_generated_objects(dc):
|
||||||
|
checks = []
|
||||||
|
|
||||||
|
# Check 1: All devices created
|
||||||
|
expected_devices = (
|
||||||
|
dc.spine_count +
|
||||||
|
dc.leaf_pair_count * 2 +
|
||||||
|
dc.border_leaf_count +
|
||||||
|
dc.number_of_bays
|
||||||
|
)
|
||||||
|
if len(dc.devices) != expected_devices:
|
||||||
|
checks.append("ERROR: Device count mismatch")
|
||||||
|
|
||||||
|
# Check 2: No duplicate IPs
|
||||||
|
if has_duplicate_ips(dc.devices):
|
||||||
|
checks.append("ERROR: Duplicate IP addresses")
|
||||||
|
|
||||||
|
# Check 3: All BGP sessions configured
|
||||||
|
if missing_bgp_sessions(dc.devices):
|
||||||
|
checks.append("ERROR: Missing BGP sessions")
|
||||||
|
|
||||||
|
# Check 4: MLAG pairs valid
|
||||||
|
if invalid_mlag_pairs(dc.devices):
|
||||||
|
checks.append("ERROR: Invalid MLAG configuration")
|
||||||
|
|
||||||
|
return checks
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📐 Mermaid Diagram Structure
|
||||||
|
|
||||||
|
### High-Level Datacenter Diagram
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Site[Site: Paris-DC1]
|
||||||
|
DC[Datacenter: DC1<br/>bays=2, spines=3]
|
||||||
|
|
||||||
|
Site --> DC
|
||||||
|
|
||||||
|
DC --> Spines[Spine Layer<br/>spine1-3-DC1]
|
||||||
|
DC --> Leafs[Leaf Layer<br/>leaf1-4-DC1]
|
||||||
|
DC --> Borders[Border Layer<br/>borderleaf1-2-DC1]
|
||||||
|
DC --> Bays[Bay Layer<br/>bay1-2]
|
||||||
|
|
||||||
|
Bays --> Bay1[Bay 1]
|
||||||
|
Bays --> Bay2[Bay 2]
|
||||||
|
|
||||||
|
Bay1 --> Access1[access1-DC1]
|
||||||
|
Bay2 --> Access2[access2-DC1]
|
||||||
|
|
||||||
|
Access1 --> LeafPair1[Leaf Pair 1<br/>leaf1-2-DC1]
|
||||||
|
Access2 --> LeafPair2[Leaf Pair 2<br/>leaf3-4-DC1]
|
||||||
|
|
||||||
|
LeafPair1 --> Spines
|
||||||
|
LeafPair2 --> Spines
|
||||||
|
Borders --> Spines
|
||||||
|
```
|
||||||
|
|
||||||
|
### Detailed Device-Level Diagram
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph DC1
|
||||||
|
S1[spine1-DC1<br/>10.1.0.11]
|
||||||
|
S2[spine2-DC1<br/>10.1.0.12]
|
||||||
|
S3[spine3-DC1<br/>10.1.0.13]
|
||||||
|
|
||||||
|
L1[leaf1-DC1<br/>10.1.0.21<br/>VTEP: 10.1.1.21]
|
||||||
|
L2[leaf2-DC1<br/>10.1.0.22<br/>VTEP: 10.1.1.21]
|
||||||
|
L3[leaf3-DC1<br/>10.1.0.23<br/>VTEP: 10.1.1.23]
|
||||||
|
L4[leaf4-DC1<br/>10.1.0.24<br/>VTEP: 10.1.1.23]
|
||||||
|
|
||||||
|
A1[access1-DC1<br/>Bay 1]
|
||||||
|
A2[access2-DC1<br/>Bay 2]
|
||||||
|
|
||||||
|
L1 -.MLAG.- L2
|
||||||
|
L3 -.MLAG.- L4
|
||||||
|
|
||||||
|
S1 --> L1
|
||||||
|
S1 --> L2
|
||||||
|
S1 --> L3
|
||||||
|
S1 --> L4
|
||||||
|
|
||||||
|
S2 --> L1
|
||||||
|
S2 --> L2
|
||||||
|
S2 --> L3
|
||||||
|
S2 --> L4
|
||||||
|
|
||||||
|
S3 --> L1
|
||||||
|
S3 --> L2
|
||||||
|
S3 --> L3
|
||||||
|
S3 --> L4
|
||||||
|
|
||||||
|
L1 --> A1
|
||||||
|
L2 --> A1
|
||||||
|
L3 --> A2
|
||||||
|
L4 --> A2
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Summary: What Infrahub Will Generate
|
||||||
|
|
||||||
|
**From Single "Datacenter" Object Input**:
|
||||||
|
|
||||||
|
✅ **27 Device Objects** (for DC with 2 bays):
|
||||||
|
- 3 Spines
|
||||||
|
- 4 Leafs
|
||||||
|
- 2 Border Leafs
|
||||||
|
- 2 Access switches
|
||||||
|
|
||||||
|
✅ **~150 Interface Objects**:
|
||||||
|
- Physical interfaces
|
||||||
|
- Loopback interfaces
|
||||||
|
- VLAN interfaces (MLAG)
|
||||||
|
|
||||||
|
✅ **~90 IP Address Objects**:
|
||||||
|
- Management IPs
|
||||||
|
- Loopback IPs
|
||||||
|
- P2P link IPs
|
||||||
|
- MLAG peer IPs
|
||||||
|
|
||||||
|
✅ **~40 BGP Session Objects**:
|
||||||
|
- Spine-to-Leaf sessions
|
||||||
|
- Leaf MLAG iBGP sessions
|
||||||
|
- Border-to-DCI sessions
|
||||||
|
|
||||||
|
✅ **3 MLAG Pair Objects**:
|
||||||
|
- Leaf pairs
|
||||||
|
- Border leaf pair
|
||||||
|
|
||||||
|
✅ **6 Subnet Objects**:
|
||||||
|
- Loopback0, Loopback1
|
||||||
|
- Spine-Leaf P2P, Leaf-Access P2P
|
||||||
|
- MLAG Peer, Tenant VLANs
|
||||||
|
|
||||||
|
**All from ~10 input attributes!** 🎯
|
||||||
|
|
||||||
|
This is the power of the generator pattern - infrastructure as data!
|
||||||
538
infrahub/generator.md
Normal file
538
infrahub/generator.md
Normal file
@@ -0,0 +1,538 @@
|
|||||||
|
# Datacenter Generator - Visual Diagrams
|
||||||
|
|
||||||
|
## 1. Generator Concept - High Level
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph Input["📥 INPUT"]
|
||||||
|
DC1[Datacenter: DC1<br/>---<br/>dc_id: 1<br/>bays: 2<br/>dci_enabled: false]
|
||||||
|
DC2[Datacenter: DC2<br/>---<br/>dc_id: 2<br/>bays: 2<br/>dci_enabled: false]
|
||||||
|
DCI_Config[DCI Configuration<br/>---<br/>Manual/External<br/>IP: 10.253.254.x]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Logic["⚙️ DATACENTER GENERATOR"]
|
||||||
|
Gen1[DC1 Generator:<br/>Create 11 devices<br/>Border eth12: shutdown]
|
||||||
|
Gen2[DC2 Generator:<br/>Create 11 devices<br/>Border eth12: shutdown]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Output1["📤 DC1 OUTPUT"]
|
||||||
|
Dev1[11 Device Objects]
|
||||||
|
Int1[~50 Interface Objects]
|
||||||
|
IP1[~30 IP Addresses]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Output2["📤 DC2 OUTPUT"]
|
||||||
|
Dev2[11 Device Objects]
|
||||||
|
Int2[~50 Interface Objects]
|
||||||
|
IP2[~30 IP Addresses]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Manual["🔧 MANUAL DCI SETUP"]
|
||||||
|
DCIDevice[DCI Device<br/>Loopback: 10.253.0.1<br/>ASN: 65000]
|
||||||
|
UpdateDC1[Update DC1:<br/>dci_enabled: true<br/>dci_remote_dc_id: 2]
|
||||||
|
UpdateDC2[Update DC2:<br/>dci_enabled: true<br/>dci_remote_dc_id: 1]
|
||||||
|
end
|
||||||
|
|
||||||
|
DC1 --> Gen1
|
||||||
|
DC2 --> Gen2
|
||||||
|
|
||||||
|
Gen1 --> Dev1
|
||||||
|
Gen1 --> Int1
|
||||||
|
Gen1 --> IP1
|
||||||
|
|
||||||
|
Gen2 --> Dev2
|
||||||
|
Gen2 --> Int2
|
||||||
|
Gen2 --> IP2
|
||||||
|
|
||||||
|
Output1 --> Manual
|
||||||
|
Output2 --> Manual
|
||||||
|
DCI_Config --> DCIDevice
|
||||||
|
DCIDevice --> UpdateDC1
|
||||||
|
DCIDevice --> UpdateDC2
|
||||||
|
|
||||||
|
style DC1 fill:#e1f5ff
|
||||||
|
style DC2 fill:#e1f5ff
|
||||||
|
style Manual fill:#fff9c4
|
||||||
|
style DCIDevice fill:#ffccbc
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Datacenter Hierarchy
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Org[Organization]
|
||||||
|
Site[Site: Paris-DC1<br/>Location: Paris, France]
|
||||||
|
DC[Datacenter: DC1<br/>dc_id: 1<br/>bays: 2<br/>spines: 3]
|
||||||
|
|
||||||
|
Org --> Site
|
||||||
|
Site --> DC
|
||||||
|
|
||||||
|
DC --> SpineLayer[Spine Layer]
|
||||||
|
DC --> LeafLayer[Leaf Layer]
|
||||||
|
DC --> BorderLayer[Border Layer]
|
||||||
|
DC --> BayLayer[Bay Layer]
|
||||||
|
DC --> Subnets[IP Subnets]
|
||||||
|
|
||||||
|
SpineLayer --> S1[spine1-DC1<br/>ASN: 65100]
|
||||||
|
SpineLayer --> S2[spine2-DC1<br/>ASN: 65100]
|
||||||
|
SpineLayer --> S3[spine3-DC1<br/>ASN: 65100]
|
||||||
|
|
||||||
|
LeafLayer --> LP1[Leaf Pair 1<br/>ASN: 65101]
|
||||||
|
LeafLayer --> LP2[Leaf Pair 2<br/>ASN: 65102]
|
||||||
|
|
||||||
|
LP1 --> L1[leaf1-DC1<br/>10.1.0.21]
|
||||||
|
LP1 --> L2[leaf2-DC1<br/>10.1.0.22]
|
||||||
|
LP2 --> L3[leaf3-DC1<br/>10.1.0.23]
|
||||||
|
LP2 --> L4[leaf4-DC1<br/>10.1.0.24]
|
||||||
|
|
||||||
|
BorderLayer --> BP[Border Pair<br/>ASN: 65103]
|
||||||
|
BP --> B1[borderleaf1-DC1]
|
||||||
|
BP --> B2[borderleaf2-DC1]
|
||||||
|
|
||||||
|
BayLayer --> Bay1[Bay 1]
|
||||||
|
BayLayer --> Bay2[Bay 2]
|
||||||
|
|
||||||
|
Bay1 --> A1[access1-DC1]
|
||||||
|
Bay2 --> A2[access2-DC1]
|
||||||
|
|
||||||
|
Subnets --> Sub1[10.1.0.0/24<br/>Loopback0]
|
||||||
|
Subnets --> Sub2[10.1.1.0/24<br/>Loopback1]
|
||||||
|
Subnets --> Sub3[10.1.10.0/24<br/>Spine-Leaf P2P]
|
||||||
|
Subnets --> Sub4[10.1.20.0/24<br/>Leaf-Access P2P]
|
||||||
|
|
||||||
|
style DC fill:#ffecb3
|
||||||
|
style LP1 fill:#b3e5fc
|
||||||
|
style LP2 fill:#b3e5fc
|
||||||
|
style Bay1 fill:#c8e6c9
|
||||||
|
style Bay2 fill:#c8e6c9
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Bay-to-Leaf Assignment Logic
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph Bays["🏢 Bays"]
|
||||||
|
Bay1[Bay 1<br/>access1-DC1]
|
||||||
|
Bay2[Bay 2<br/>access2-DC1]
|
||||||
|
Bay3[Bay 3<br/>access3-DC1]
|
||||||
|
Bay4[Bay 4<br/>access4-DC1]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph LeafPairs["🔀 Leaf Pairs - MLAG"]
|
||||||
|
LP1[Leaf Pair 1<br/>leaf1-DC1 ↔ leaf2-DC1<br/>ASN: 65101]
|
||||||
|
LP2[Leaf Pair 2<br/>leaf3-DC1 ↔ leaf4-DC1<br/>ASN: 65102]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Spines["⬆️ Spine Layer"]
|
||||||
|
S1[spine1-DC1]
|
||||||
|
S2[spine2-DC1]
|
||||||
|
S3[spine3-DC1]
|
||||||
|
end
|
||||||
|
|
||||||
|
Bay1 -.2 uplinks.- LP1
|
||||||
|
Bay2 -.2 uplinks.- LP1
|
||||||
|
Bay3 -.2 uplinks.- LP2
|
||||||
|
Bay4 -.2 uplinks.- LP2
|
||||||
|
|
||||||
|
LP1 --> S1
|
||||||
|
LP1 --> S2
|
||||||
|
LP1 --> S3
|
||||||
|
LP2 --> S1
|
||||||
|
LP2 --> S2
|
||||||
|
LP2 --> S3
|
||||||
|
|
||||||
|
style Bay1 fill:#c8e6c9
|
||||||
|
style Bay2 fill:#c8e6c9
|
||||||
|
style Bay3 fill:#ffccbc
|
||||||
|
style Bay4 fill:#ffccbc
|
||||||
|
style LP1 fill:#b3e5fc
|
||||||
|
style LP2 fill:#b3e5fc
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Complete DC1 Physical Topology
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph DCI["DCI LAYER - Inter-DC"]
|
||||||
|
DCID[DCI Switch<br/>10.253.0.1<br/>ASN: 65000]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Border["BORDER LEAF - DCI Gateway"]
|
||||||
|
B1[borderleaf1-DC1<br/>10.1.0.31<br/>eth12: shutdown or active]
|
||||||
|
B2[borderleaf2-DC1<br/>10.1.0.32<br/>eth12: shutdown or active]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Spine["SPINE LAYER - L3 Core"]
|
||||||
|
S1[spine1-DC1<br/>10.1.0.11<br/>ASN: 65100]
|
||||||
|
S2[spine2-DC1<br/>10.1.0.12<br/>ASN: 65100]
|
||||||
|
S3[spine3-DC1<br/>10.1.0.13<br/>ASN: 65100]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Leaf["LEAF LAYER - Aggregation + VXLAN"]
|
||||||
|
subgraph Pair1["MLAG Pair 1 - ASN: 65101"]
|
||||||
|
L1[leaf1-DC1<br/>10.1.0.21<br/>VTEP: 10.1.1.21]
|
||||||
|
L2[leaf2-DC1<br/>10.1.0.22<br/>VTEP: 10.1.1.21]
|
||||||
|
end
|
||||||
|
subgraph Pair2["MLAG Pair 2 - ASN: 65102"]
|
||||||
|
L3[leaf3-DC1<br/>10.1.0.23<br/>VTEP: 10.1.1.23]
|
||||||
|
L4[leaf4-DC1<br/>10.1.0.24<br/>VTEP: 10.1.1.23]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Access["ACCESS LAYER - Rack/Bay ToR"]
|
||||||
|
A1[access1-DC1<br/>Bay 1<br/>L2 Switch]
|
||||||
|
A2[access2-DC1<br/>Bay 2<br/>L2 Switch]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Hosts["HOST LAYER"]
|
||||||
|
H1[host1-DC1<br/>172.16.100.10]
|
||||||
|
H2[host2-DC1<br/>172.16.200.10]
|
||||||
|
end
|
||||||
|
|
||||||
|
DCID -.Optional DCI.- B1
|
||||||
|
DCID -.Optional DCI.- B2
|
||||||
|
|
||||||
|
S1 -.eBGP.- L1
|
||||||
|
S1 -.eBGP.- L2
|
||||||
|
S1 -.eBGP.- L3
|
||||||
|
S1 -.eBGP.- L4
|
||||||
|
S1 -.eBGP.- B1
|
||||||
|
S1 -.eBGP.- B2
|
||||||
|
|
||||||
|
S2 -.eBGP.- L1
|
||||||
|
S2 -.eBGP.- L2
|
||||||
|
S2 -.eBGP.- L3
|
||||||
|
S2 -.eBGP.- L4
|
||||||
|
S2 -.eBGP.- B1
|
||||||
|
S2 -.eBGP.- B2
|
||||||
|
|
||||||
|
S3 -.eBGP.- L1
|
||||||
|
S3 -.eBGP.- L2
|
||||||
|
S3 -.eBGP.- L3
|
||||||
|
S3 -.eBGP.- L4
|
||||||
|
S3 -.eBGP.- B1
|
||||||
|
S3 -.eBGP.- B2
|
||||||
|
|
||||||
|
L1 ---|MLAG| L2
|
||||||
|
L3 ---|MLAG| L4
|
||||||
|
B1 ---|MLAG| B2
|
||||||
|
|
||||||
|
L1 -->|eth7| A1
|
||||||
|
L2 -->|eth7| A1
|
||||||
|
L3 -->|eth7| A2
|
||||||
|
L4 -->|eth7| A2
|
||||||
|
|
||||||
|
A1 -->|eth10| H1
|
||||||
|
A2 -->|eth10| H2
|
||||||
|
|
||||||
|
style DCID fill:#ffccbc
|
||||||
|
style S1 fill:#ffccbc
|
||||||
|
style S2 fill:#ffccbc
|
||||||
|
style S3 fill:#ffccbc
|
||||||
|
style L1 fill:#b3e5fc
|
||||||
|
style L2 fill:#b3e5fc
|
||||||
|
style L3 fill:#b3e5fc
|
||||||
|
style L4 fill:#b3e5fc
|
||||||
|
style A1 fill:#c8e6c9
|
||||||
|
style A2 fill:#c8e6c9
|
||||||
|
style B1 fill:#f8bbd0
|
||||||
|
style B2 fill:#f8bbd0
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. IP Address Generation Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Start[Datacenter Object<br/>dc_id: 1, bays: 2]
|
||||||
|
|
||||||
|
Start --> GenSubnets[Generate Subnets<br/>from dc_id]
|
||||||
|
|
||||||
|
GenSubnets --> Sub1[10.1.0.0/24<br/>Loopback0]
|
||||||
|
GenSubnets --> Sub2[10.1.1.0/24<br/>Loopback1]
|
||||||
|
GenSubnets --> Sub3[10.1.10.0/24<br/>Spine-Leaf P2P]
|
||||||
|
GenSubnets --> Sub4[10.1.20.0/24<br/>Leaf-Access P2P]
|
||||||
|
GenSubnets --> Sub5[10.1.255.0/24<br/>MLAG Peer]
|
||||||
|
GenSubnets --> Sub6[10.255.0.0/24<br/>Management]
|
||||||
|
|
||||||
|
Sub1 --> AllocLo0[Allocate Loopback0<br/>to Spines & Leafs]
|
||||||
|
Sub2 --> AllocLo1[Allocate Loopback1<br/>to Leafs - shared in pairs]
|
||||||
|
Sub3 --> AllocP2P1[Allocate /31s<br/>for Spine-Leaf links]
|
||||||
|
Sub4 --> AllocP2P2[Allocate /31s<br/>for Leaf-Access links]
|
||||||
|
Sub5 --> AllocMLAG[Allocate /30s<br/>for MLAG peers]
|
||||||
|
Sub6 --> AllocMgmt[Allocate Management IPs<br/>to all devices]
|
||||||
|
|
||||||
|
AllocLo0 --> Spine1IP[spine1: 10.1.0.11/32]
|
||||||
|
AllocLo0 --> Leaf1IP[leaf1: 10.1.0.21/32]
|
||||||
|
|
||||||
|
AllocLo1 --> Leaf1VTEP[leaf1-2: 10.1.1.21/32 - shared]
|
||||||
|
|
||||||
|
AllocP2P1 --> Link1[spine1-leaf1: 10.1.10.0/31]
|
||||||
|
|
||||||
|
AllocP2P2 --> Link2[leaf1-access1: 10.1.20.0/31]
|
||||||
|
|
||||||
|
AllocMLAG --> MLAG1[leaf1-2 peer: 10.1.255.1-2/30]
|
||||||
|
|
||||||
|
AllocMgmt --> Mgmt1[spine1: 10.255.0.11]
|
||||||
|
|
||||||
|
style Start fill:#ffecb3
|
||||||
|
style Sub1 fill:#e1f5ff
|
||||||
|
style Sub2 fill:#e1f5ff
|
||||||
|
style Sub3 fill:#e1f5ff
|
||||||
|
style Sub4 fill:#e1f5ff
|
||||||
|
style Sub5 fill:#e1f5ff
|
||||||
|
style Sub6 fill:#e1f5ff
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Device Generation Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
DC[Datacenter: DC1<br/>bays: 2]
|
||||||
|
|
||||||
|
DC --> CalcLeafs[Calculate:<br/>leaf_pairs = ceil - bays / 2 - = 1<br/>total_leafs = 1 * 2 = 2]
|
||||||
|
|
||||||
|
CalcLeafs --> GenSpines[Generate Spines<br/>count: 3 - fixed]
|
||||||
|
CalcLeafs --> GenLeafs[Generate Leafs<br/>count: 4 - computed]
|
||||||
|
CalcLeafs --> GenBorders[Generate Border Leafs<br/>count: 2 - fixed]
|
||||||
|
CalcLeafs --> GenAccess[Generate Access<br/>count: 2 - from bays]
|
||||||
|
|
||||||
|
GenSpines --> S1[spine1-DC1]
|
||||||
|
GenSpines --> S2[spine2-DC1]
|
||||||
|
GenSpines --> S3[spine3-DC1]
|
||||||
|
|
||||||
|
GenLeafs --> LP1[Create MLAG Pair 1]
|
||||||
|
GenLeafs --> LP2[Create MLAG Pair 2]
|
||||||
|
|
||||||
|
LP1 --> L1[leaf1-DC1]
|
||||||
|
LP1 --> L2[leaf2-DC1]
|
||||||
|
LP2 --> L3[leaf3-DC1]
|
||||||
|
LP2 --> L4[leaf4-DC1]
|
||||||
|
|
||||||
|
GenBorders --> BP[Create Border Pair]
|
||||||
|
BP --> B1[borderleaf1-DC1]
|
||||||
|
BP --> B2[borderleaf2-DC1]
|
||||||
|
|
||||||
|
GenAccess --> AssignBays[Assign Bays to Leaf Pairs]
|
||||||
|
AssignBays --> A1Config[Bay 1 → Leaf Pair 1<br/>access1-DC1]
|
||||||
|
AssignBays --> A2Config[Bay 2 → Leaf Pair 1<br/>access2-DC1]
|
||||||
|
|
||||||
|
A1Config --> A1[access1-DC1]
|
||||||
|
A2Config --> A2[access2-DC1]
|
||||||
|
|
||||||
|
style DC fill:#ffecb3
|
||||||
|
style LP1 fill:#b3e5fc
|
||||||
|
style LP2 fill:#b3e5fc
|
||||||
|
style BP fill:#f8bbd0
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Scaling Scenario - Adding Bay 3
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph Current["📦 Current State - 2 Bays"]
|
||||||
|
CurDC[Datacenter: DC1<br/>bays: 2<br/>leaf_pairs: 1]
|
||||||
|
CurLP1[Leaf Pair 1<br/>leaf1-2]
|
||||||
|
CurBay1[Bay 1 → access1]
|
||||||
|
CurBay2[Bay 2 → access2]
|
||||||
|
|
||||||
|
CurDC --> CurLP1
|
||||||
|
CurLP1 --> CurBay1
|
||||||
|
CurLP1 --> CurBay2
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Action["⚙️ User Action"]
|
||||||
|
AddBay[Add Bay 3<br/>number_of_bays: 2 → 3]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Generator["🔄 Generator Logic"]
|
||||||
|
Check[Check:<br/>bays=3 > pairs*2=2?<br/>YES → Need new pair]
|
||||||
|
CreatePair[Create Leaf Pair 2<br/>leaf3-DC1, leaf4-DC1]
|
||||||
|
CreateAccess[Create access3-DC1]
|
||||||
|
AssignBay[Assign Bay 3 → Pair 2]
|
||||||
|
AllocIPs[Allocate IPs]
|
||||||
|
CreateLinks[Create Interfaces]
|
||||||
|
ConfigBGP[Configure BGP<br/>ASN: 65102]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Result["✅ New State - 3 Bays"]
|
||||||
|
NewDC[Datacenter: DC1<br/>bays: 3<br/>leaf_pairs: 2]
|
||||||
|
NewLP1[Leaf Pair 1<br/>leaf1-2<br/>ASN: 65101]
|
||||||
|
NewLP2[Leaf Pair 2<br/>leaf3-4<br/>ASN: 65102]
|
||||||
|
NewBay1[Bay 1 → access1]
|
||||||
|
NewBay2[Bay 2 → access2]
|
||||||
|
NewBay3[Bay 3 → access3]
|
||||||
|
|
||||||
|
NewDC --> NewLP1
|
||||||
|
NewDC --> NewLP2
|
||||||
|
NewLP1 --> NewBay1
|
||||||
|
NewLP1 --> NewBay2
|
||||||
|
NewLP2 --> NewBay3
|
||||||
|
end
|
||||||
|
|
||||||
|
Current --> AddBay
|
||||||
|
AddBay --> Check
|
||||||
|
Check --> CreatePair
|
||||||
|
CreatePair --> CreateAccess
|
||||||
|
CreateAccess --> AssignBay
|
||||||
|
AssignBay --> AllocIPs
|
||||||
|
AllocIPs --> CreateLinks
|
||||||
|
CreateLinks --> ConfigBGP
|
||||||
|
ConfigBGP --> Result
|
||||||
|
|
||||||
|
style AddBay fill:#fff59d
|
||||||
|
style Check fill:#ffccbc
|
||||||
|
style Result fill:#c8e6c9
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Infrahub Generator Workflow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant User
|
||||||
|
participant Infrahub
|
||||||
|
participant Generator
|
||||||
|
participant Validator
|
||||||
|
participant GraphQL
|
||||||
|
participant Devices
|
||||||
|
|
||||||
|
User->>Infrahub: Create Datacenter Object<br/>(name, dc_id, bays, etc.)
|
||||||
|
Infrahub->>Validator: Pre-Generation Validation
|
||||||
|
Validator-->>Infrahub: ✅ Valid Input
|
||||||
|
|
||||||
|
Infrahub->>Generator: Trigger Generator
|
||||||
|
|
||||||
|
Generator->>Generator: Compute Derived Values<br/>(leaf_pairs, subnets, etc.)
|
||||||
|
|
||||||
|
loop For Each Layer
|
||||||
|
Generator->>Devices: Create Spine Devices
|
||||||
|
Generator->>Devices: Create Leaf Devices
|
||||||
|
Generator->>Devices: Create Access Devices
|
||||||
|
end
|
||||||
|
|
||||||
|
loop For Each Device
|
||||||
|
Generator->>Devices: Create Interfaces
|
||||||
|
Generator->>Devices: Allocate IP Addresses
|
||||||
|
Generator->>Devices: Generate BGP Config
|
||||||
|
end
|
||||||
|
|
||||||
|
Generator->>Validator: Post-Generation Validation
|
||||||
|
Validator-->>Generator: ✅ All Objects Valid
|
||||||
|
|
||||||
|
Generator->>GraphQL: Commit All Objects
|
||||||
|
GraphQL-->>Infrahub: Objects Created
|
||||||
|
|
||||||
|
Infrahub-->>User: ✅ Datacenter Generated<br/>27 devices, 150 interfaces, 90 IPs
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Configuration Generation Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph Infrahub["📊 Infrahub - Source of Truth"]
|
||||||
|
DeviceDB[(Device Objects<br/>Interfaces<br/>IPs<br/>BGP Sessions)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Generator["⚙️ Config Generator"]
|
||||||
|
Templates[Jinja2 Templates<br/>by Device Role]
|
||||||
|
RenderEngine[Template Renderer]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Output["📄 Generated Configs"]
|
||||||
|
SpineConfig[spine1-DC1.cfg]
|
||||||
|
LeafConfig[leaf1-DC1.cfg]
|
||||||
|
AccessConfig[access1-DC1.cfg]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Deployment["🚀 Deployment"]
|
||||||
|
Validation[Config Validation]
|
||||||
|
Push[Push to Devices<br/>via eAPI/NETCONF]
|
||||||
|
end
|
||||||
|
|
||||||
|
DeviceDB -->|Query Device Data| RenderEngine
|
||||||
|
Templates --> RenderEngine
|
||||||
|
|
||||||
|
RenderEngine --> SpineConfig
|
||||||
|
RenderEngine --> LeafConfig
|
||||||
|
RenderEngine --> AccessConfig
|
||||||
|
|
||||||
|
SpineConfig --> Validation
|
||||||
|
LeafConfig --> Validation
|
||||||
|
AccessConfig --> Validation
|
||||||
|
|
||||||
|
Validation --> Push
|
||||||
|
|
||||||
|
Push --> Devices[Physical Devices]
|
||||||
|
|
||||||
|
style Infrahub fill:#e1f5ff
|
||||||
|
style Generator fill:#fff9c4
|
||||||
|
style Output fill:#c8e6c9
|
||||||
|
style Deployment fill:#ffccbc
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. Complete Data Model Relationships
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
ORGANIZATION ||--o{ SITE : contains
|
||||||
|
SITE ||--o{ DATACENTER : contains
|
||||||
|
SITE ||--o{ IP_PREFIX : manages
|
||||||
|
|
||||||
|
DATACENTER ||--|{ SUBNET : generates
|
||||||
|
DATACENTER ||--|{ DEVICE : generates
|
||||||
|
DATACENTER ||--|{ MLAG_PAIR : generates
|
||||||
|
|
||||||
|
DEVICE ||--|{ INTERFACE : has
|
||||||
|
INTERFACE ||--o| IP_ADDRESS : assigned
|
||||||
|
INTERFACE ||--o| BGP_SESSION : endpoint
|
||||||
|
|
||||||
|
DEVICE }|--|| ROLE : has
|
||||||
|
DEVICE }o--o| MLAG_PAIR : member_of
|
||||||
|
|
||||||
|
MLAG_PAIR ||--|| DEVICE : primary
|
||||||
|
MLAG_PAIR ||--|| DEVICE : secondary
|
||||||
|
|
||||||
|
BGP_SESSION }o--|| INTERFACE : local
|
||||||
|
BGP_SESSION }o--|| INTERFACE : remote
|
||||||
|
|
||||||
|
SUBNET ||--|{ IP_ADDRESS : contains
|
||||||
|
IP_PREFIX ||--|{ SUBNET : parent
|
||||||
|
|
||||||
|
ORGANIZATION {
|
||||||
|
string name
|
||||||
|
}
|
||||||
|
|
||||||
|
SITE {
|
||||||
|
string name
|
||||||
|
string location
|
||||||
|
}
|
||||||
|
|
||||||
|
DATACENTER {
|
||||||
|
string name
|
||||||
|
int dc_id
|
||||||
|
int number_of_bays
|
||||||
|
int spine_count
|
||||||
|
string parent_subnet
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE {
|
||||||
|
string hostname
|
||||||
|
string role
|
||||||
|
string mgmt_ip
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERFACE {
|
||||||
|
string name
|
||||||
|
string type
|
||||||
|
int mtu
|
||||||
|
}
|
||||||
|
|
||||||
|
IP_ADDRESS {
|
||||||
|
string address
|
||||||
|
int prefix_length
|
||||||
|
}
|
||||||
|
|
||||||
|
BGP_SESSION {
|
||||||
|
int local_asn
|
||||||
|
int remote_asn
|
||||||
|
}
|
||||||
|
```
|
||||||
111
infrahub/schema/01_organization.yml
Normal file
111
infrahub/schema/01_organization.yml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: Organization
|
||||||
|
namespace: Core
|
||||||
|
label: "Organization"
|
||||||
|
icon: "mdi:domain"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["name__value"]
|
||||||
|
display_label: "{{ record.name__value }}"
|
||||||
|
order_by:
|
||||||
|
- name__value
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "Organization name"
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Organization description"
|
||||||
|
- name: asn_base
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 65000
|
||||||
|
description: "Base ASN for BGP allocation (e.g., 65000)"
|
||||||
|
relationships:
|
||||||
|
- name: sites
|
||||||
|
peer: LocationSite
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Sites belonging to this organization"
|
||||||
|
- name: ip_namespaces
|
||||||
|
peer: IpamNamespace
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "IP namespaces managed by this organization"
|
||||||
|
|
||||||
|
- name: Site
|
||||||
|
namespace: Location
|
||||||
|
label: "Site"
|
||||||
|
icon: "mdi:office-building"
|
||||||
|
include_in_menu: true
|
||||||
|
menu_placement: "CoreOrganization"
|
||||||
|
human_friendly_id: ["name__value"]
|
||||||
|
display_label: "{{ record.name__value }}"
|
||||||
|
order_by:
|
||||||
|
- name__value
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "Site name (e.g., Paris-DC)"
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Site description"
|
||||||
|
- name: location
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Physical location (e.g., Paris, France)"
|
||||||
|
- name: facility_id
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Facility identifier"
|
||||||
|
- name: status
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "active"
|
||||||
|
choices:
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
description: Site is operational
|
||||||
|
color: "#7fbf7f"
|
||||||
|
- name: planned
|
||||||
|
label: Planned
|
||||||
|
description: Site is being planned
|
||||||
|
color: "#ffd966"
|
||||||
|
- name: maintenance
|
||||||
|
label: Maintenance
|
||||||
|
description: Site under maintenance
|
||||||
|
color: "#ff9999"
|
||||||
|
- name: decommissioned
|
||||||
|
label: Decommissioned
|
||||||
|
description: Site decommissioned
|
||||||
|
color: "#cccccc"
|
||||||
|
relationships:
|
||||||
|
- name: organization
|
||||||
|
peer: CoreOrganization
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Parent organization"
|
||||||
|
- name: datacenters
|
||||||
|
peer: InfraDatacenter
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Datacenters at this site"
|
||||||
|
- name: parent_prefix
|
||||||
|
peer: IpamIPPrefix
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Parent IP prefix for this site"
|
||||||
164
infrahub/schema/02_ipam.yml
Normal file
164
infrahub/schema/02_ipam.yml
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: Namespace
|
||||||
|
namespace: Ipam
|
||||||
|
label: "IP Namespace"
|
||||||
|
icon: "mdi:ip-network"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["name__value"]
|
||||||
|
display_label: "{{ record.name__value }}"
|
||||||
|
order_by:
|
||||||
|
- name__value
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "Namespace name (e.g., Global, Tenant1)"
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Namespace description"
|
||||||
|
relationships:
|
||||||
|
- name: organization
|
||||||
|
peer: CoreOrganization
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
|
||||||
|
- name: IPPrefix
|
||||||
|
namespace: Ipam
|
||||||
|
label: "IP Prefix"
|
||||||
|
icon: "mdi:ip-network-outline"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["prefix__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.prefix__value, record.description__value])) }}"
|
||||||
|
order_by:
|
||||||
|
- prefix__value
|
||||||
|
attributes:
|
||||||
|
- name: prefix
|
||||||
|
kind: IPNetwork
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "IP Prefix (e.g., 10.1.0.0/24)"
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Prefix description"
|
||||||
|
- name: prefix_type
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "pool"
|
||||||
|
choices:
|
||||||
|
- name: pool
|
||||||
|
label: Pool
|
||||||
|
description: IP address pool
|
||||||
|
- name: loopback
|
||||||
|
label: Loopback
|
||||||
|
description: Loopback addresses
|
||||||
|
- name: p2p
|
||||||
|
label: Point-to-Point
|
||||||
|
description: Point-to-point links
|
||||||
|
- name: management
|
||||||
|
label: Management
|
||||||
|
description: Management network
|
||||||
|
- name: tenant
|
||||||
|
label: Tenant
|
||||||
|
description: Tenant/VLAN network
|
||||||
|
- name: vtep
|
||||||
|
label: VTEP
|
||||||
|
description: VXLAN VTEP addresses
|
||||||
|
- name: mlag
|
||||||
|
label: MLAG
|
||||||
|
description: MLAG peer links
|
||||||
|
- name: status
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "active"
|
||||||
|
choices:
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
- name: reserved
|
||||||
|
label: Reserved
|
||||||
|
- name: deprecated
|
||||||
|
label: Deprecated
|
||||||
|
relationships:
|
||||||
|
- name: namespace
|
||||||
|
peer: IpamNamespace
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
- name: parent
|
||||||
|
peer: IpamIPPrefix
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Parent prefix"
|
||||||
|
- name: children
|
||||||
|
peer: IpamIPPrefix
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Child prefixes"
|
||||||
|
- name: datacenter
|
||||||
|
peer: InfraDatacenter
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Associated datacenter"
|
||||||
|
- name: vrf
|
||||||
|
peer: NetworkVRF
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
|
||||||
|
- name: IPAddress
|
||||||
|
namespace: Ipam
|
||||||
|
label: "IP Address"
|
||||||
|
icon: "mdi:ip"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["address__value"]
|
||||||
|
display_label: "{{ record.address__value }}"
|
||||||
|
order_by:
|
||||||
|
- address__value
|
||||||
|
attributes:
|
||||||
|
- name: address
|
||||||
|
kind: IPHost
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "IP Address with mask (e.g., 10.1.0.1/32)"
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "IP address description"
|
||||||
|
- name: status
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "active"
|
||||||
|
choices:
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
- name: reserved
|
||||||
|
label: Reserved
|
||||||
|
- name: deprecated
|
||||||
|
label: Deprecated
|
||||||
|
relationships:
|
||||||
|
- name: prefix
|
||||||
|
peer: IpamIPPrefix
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
- name: interface
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Interface using this IP"
|
||||||
|
- name: vrf
|
||||||
|
peer: NetworkVRF
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
211
infrahub/schema/03_datacenter.yml
Normal file
211
infrahub/schema/03_datacenter.yml
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: Datacenter
|
||||||
|
namespace: Infra
|
||||||
|
label: "Datacenter"
|
||||||
|
icon: "mdi:server-network"
|
||||||
|
include_in_menu: true
|
||||||
|
menu_placement: "LocationSite"
|
||||||
|
human_friendly_id: ["name__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.name__value, record.dc_id__value])) }}"
|
||||||
|
order_by:
|
||||||
|
- dc_id__value
|
||||||
|
generate_template: false
|
||||||
|
description: "Datacenter - Generator object that creates fabric topology"
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "Datacenter name (e.g., DC1, DC2)"
|
||||||
|
- name: dc_id
|
||||||
|
kind: Number
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "Numeric datacenter ID for IP addressing (e.g., 1, 2)"
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Datacenter description"
|
||||||
|
|
||||||
|
- name: parent_subnet
|
||||||
|
kind: IPNetwork
|
||||||
|
optional: false
|
||||||
|
description: "Address space allocation"
|
||||||
|
|
||||||
|
# Topology Configuration
|
||||||
|
- name: number_of_bays
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 2
|
||||||
|
description: "Number of bays/racks (determines leaf count)"
|
||||||
|
- name: spine_count
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 3
|
||||||
|
description: "Number of spine switches"
|
||||||
|
- name: border_leaf_count
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 2
|
||||||
|
description: "Number of border leaf switches for DCI (0 if has_border_leafs=false)"
|
||||||
|
|
||||||
|
# BGP Configuration
|
||||||
|
- name: bgp_base_asn
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 65000
|
||||||
|
description: "Base ASN for BGP (e.g., 65000)"
|
||||||
|
- name: spine_asn
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "Spine ASN (auto-calculated: base + dc_id * 100)"
|
||||||
|
|
||||||
|
# MLAG Configuration
|
||||||
|
- name: mlag_domain_id
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
default_value: "MLAG"
|
||||||
|
description: "MLAG domain identifier"
|
||||||
|
|
||||||
|
# Interface Configuration
|
||||||
|
- name: mtu
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 9214
|
||||||
|
description: "Default MTU for fabric interfaces"
|
||||||
|
|
||||||
|
# DCI Configuration (Optional)
|
||||||
|
- name: dci_enabled
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: false
|
||||||
|
description: "Enable DCI connectivity (activates border leaf eth12). Default: false (eth12 shutdown)"
|
||||||
|
- name: dci_remote_dc_id
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "Remote datacenter ID for DCI peering (required when dci_enabled=true)"
|
||||||
|
- name: has_border_leafs
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: true
|
||||||
|
description: "Include border leaf switches (set false if no DCI capability needed)"
|
||||||
|
|
||||||
|
# Computed/Derived Attributes (read-only, set by generator)
|
||||||
|
- name: leaf_pair_count
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
read_only: true
|
||||||
|
description: "Computed: ceil(number_of_bays / 2)"
|
||||||
|
- name: total_leaf_count
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
read_only: true
|
||||||
|
description: "Computed: leaf_pair_count * 2"
|
||||||
|
- name: total_access_count
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
read_only: true
|
||||||
|
description: "Computed: number_of_bays"
|
||||||
|
|
||||||
|
# Status
|
||||||
|
- name: status
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "planned"
|
||||||
|
choices:
|
||||||
|
- name: planned
|
||||||
|
label: Planned
|
||||||
|
color: "#ffd966"
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
color: "#7fbf7f"
|
||||||
|
- name: maintenance
|
||||||
|
label: Maintenance
|
||||||
|
color: "#ff9999"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: site
|
||||||
|
peer: LocationSite
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Parent site"
|
||||||
|
|
||||||
|
- name: devices
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "All devices in this datacenter (generated)"
|
||||||
|
|
||||||
|
- name: ip_prefixes
|
||||||
|
peer: IpamIPPrefix
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "IP prefixes for this datacenter (generated)"
|
||||||
|
|
||||||
|
- name: mlag_pairs
|
||||||
|
peer: NetworkMLAGDomain
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "MLAG pairs in this datacenter (generated)"
|
||||||
|
|
||||||
|
- name: Bay
|
||||||
|
namespace: Infra
|
||||||
|
label: "Bay/Rack"
|
||||||
|
icon: "mdi:server-outline"
|
||||||
|
include_in_menu: true
|
||||||
|
menu_placement: "InfraDatacenter"
|
||||||
|
human_friendly_id: ["name__value"]
|
||||||
|
display_label: "{{ record.name__value }}"
|
||||||
|
order_by:
|
||||||
|
- bay_id__value
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "Bay name (e.g., Bay-1-DC1)"
|
||||||
|
- name: bay_id
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
description: "Bay numeric ID"
|
||||||
|
- name: location
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Physical location in datacenter"
|
||||||
|
- name: rack_units
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 42
|
||||||
|
description: "Available rack units (U)"
|
||||||
|
relationships:
|
||||||
|
- name: datacenter
|
||||||
|
peer: InfraDatacenter
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
- name: access_switch
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Access switch for this bay"
|
||||||
|
- name: leaf_pair
|
||||||
|
peer: NetworkMLAGDomain
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Leaf pair serving this bay"
|
||||||
|
- name: hosts
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Host devices in this bay"
|
||||||
197
infrahub/schema/04_device.yml
Normal file
197
infrahub/schema/04_device.yml
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: Device
|
||||||
|
namespace: Network
|
||||||
|
label: "Network Device"
|
||||||
|
icon: "mdi:router"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["hostname__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.hostname__value, record.role__value])) }}"
|
||||||
|
order_by:
|
||||||
|
- hostname__value
|
||||||
|
generate_template: false
|
||||||
|
attributes:
|
||||||
|
- name: hostname
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "Device hostname (e.g., spine1-DC1)"
|
||||||
|
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Device description"
|
||||||
|
|
||||||
|
- name: role
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
choices:
|
||||||
|
- name: spine
|
||||||
|
label: Spine
|
||||||
|
description: "Spine switch (L3 core)"
|
||||||
|
color: "#ff6b6b"
|
||||||
|
- name: leaf
|
||||||
|
label: Leaf
|
||||||
|
description: "Leaf switch (ToR/Aggregation)"
|
||||||
|
color: "#4ecdc4"
|
||||||
|
- name: borderleaf
|
||||||
|
label: Border Leaf
|
||||||
|
description: "Border leaf (DCI gateway capable)"
|
||||||
|
color: "#95e1d3"
|
||||||
|
- name: access
|
||||||
|
label: Access
|
||||||
|
description: "Access switch (rack ToR)"
|
||||||
|
color: "#ffe66d"
|
||||||
|
- name: host
|
||||||
|
label: Host
|
||||||
|
description: "Host/Server device"
|
||||||
|
color: "#f1faee"
|
||||||
|
|
||||||
|
- name: platform
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
default_value: "cEOS"
|
||||||
|
description: "Device platform (e.g., cEOS, vEOS, EOS)"
|
||||||
|
|
||||||
|
- name: eos_version
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "EOS software version"
|
||||||
|
|
||||||
|
- name: serial_number
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
unique: true
|
||||||
|
description: "Device serial number"
|
||||||
|
|
||||||
|
- name: model
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Device model (e.g., DCS-7050SX3-48YC8)"
|
||||||
|
|
||||||
|
- name: management_ip_template
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Template for generating the management IP address"
|
||||||
|
|
||||||
|
- name: management_ip
|
||||||
|
kind: IPHost
|
||||||
|
optional: true
|
||||||
|
read_only: true
|
||||||
|
description: "Management IP address"
|
||||||
|
|
||||||
|
- name: status
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "active"
|
||||||
|
choices:
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
color: "#7fbf7f"
|
||||||
|
- name: planned
|
||||||
|
label: Planned
|
||||||
|
color: "#ffd966"
|
||||||
|
- name: maintenance
|
||||||
|
label: Maintenance
|
||||||
|
color: "#ff9999"
|
||||||
|
- name: failed
|
||||||
|
label: Failed
|
||||||
|
color: "#ff0000"
|
||||||
|
- name: decommissioned
|
||||||
|
label: Decommissioned
|
||||||
|
color: "#cccccc"
|
||||||
|
|
||||||
|
# Role-specific attributes
|
||||||
|
- name: spine_id
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "Spine ID (1, 2, 3...)"
|
||||||
|
|
||||||
|
- name: leaf_id
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "Leaf ID (1, 2, 3, 4...)"
|
||||||
|
|
||||||
|
- name: mlag_side
|
||||||
|
kind: Dropdown
|
||||||
|
optional: true
|
||||||
|
choices:
|
||||||
|
- name: left
|
||||||
|
label: Left (Odd)
|
||||||
|
- name: right
|
||||||
|
label: Right (Even)
|
||||||
|
description: "MLAG pairing side (left=odd, right=even)"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: datacenter
|
||||||
|
peer: InfraDatacenter
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Parent datacenter"
|
||||||
|
|
||||||
|
- name: bay
|
||||||
|
peer: InfraBay
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Bay location (for access/hosts)"
|
||||||
|
|
||||||
|
- name: site
|
||||||
|
peer: LocationSite
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Site location"
|
||||||
|
|
||||||
|
- name: interfaces
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "Device interfaces"
|
||||||
|
|
||||||
|
- name: bgp_config
|
||||||
|
peer: NetworkBGPConfig
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Component
|
||||||
|
description: "BGP configuration"
|
||||||
|
|
||||||
|
- name: ospf_config
|
||||||
|
peer: NetworkOSPFConfig
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Component
|
||||||
|
description: "OSPF configuration"
|
||||||
|
|
||||||
|
- name: mlag_domain
|
||||||
|
peer: NetworkMLAGDomain
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "MLAG domain membership"
|
||||||
|
|
||||||
|
- name: evpn_config
|
||||||
|
peer: NetworkEVPNConfig
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Component
|
||||||
|
description: "EVPN configuration"
|
||||||
|
|
||||||
|
- name: vlans
|
||||||
|
peer: NetworkVLAN
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "VLANs configured on device"
|
||||||
|
|
||||||
|
- name: vrfs
|
||||||
|
peer: NetworkVRF
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "VRFs configured on device"
|
||||||
211
infrahub/schema/05_interfaces.yml
Normal file
211
infrahub/schema/05_interfaces.yml
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: Interface
|
||||||
|
namespace: Network
|
||||||
|
label: "Interface"
|
||||||
|
icon: "mdi:ethernet"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["device__hostname__value", "name__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.name__value, record.description__value])) }}"
|
||||||
|
order_by:
|
||||||
|
- device__hostname__value
|
||||||
|
- name__value
|
||||||
|
uniqueness_constraints:
|
||||||
|
- ["device", "name__value"]
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
description: "Interface name (e.g., Ethernet1, Loopback0)"
|
||||||
|
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Interface description"
|
||||||
|
|
||||||
|
- name: interface_type
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "ethernet"
|
||||||
|
choices:
|
||||||
|
- name: ethernet
|
||||||
|
label: Ethernet
|
||||||
|
description: "Physical Ethernet interface"
|
||||||
|
- name: loopback
|
||||||
|
label: Loopback
|
||||||
|
description: "Loopback interface"
|
||||||
|
- name: port_channel
|
||||||
|
label: Port-Channel
|
||||||
|
description: "Link aggregation group"
|
||||||
|
- name: vlan
|
||||||
|
label: VLAN (SVI)
|
||||||
|
description: "VLAN interface"
|
||||||
|
- name: vxlan
|
||||||
|
label: VXLAN
|
||||||
|
description: "VXLAN tunnel interface"
|
||||||
|
- name: management
|
||||||
|
label: Management
|
||||||
|
description: "Management interface"
|
||||||
|
|
||||||
|
- name: enabled
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: true
|
||||||
|
description: "Interface administrative status"
|
||||||
|
|
||||||
|
- name: mtu
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
default_value: 9214
|
||||||
|
description: "Interface MTU"
|
||||||
|
|
||||||
|
- name: speed
|
||||||
|
kind: Dropdown
|
||||||
|
optional: true
|
||||||
|
choices:
|
||||||
|
- name: 1g
|
||||||
|
label: 1 Gbps
|
||||||
|
- name: 10g
|
||||||
|
label: 10 Gbps
|
||||||
|
- name: 25g
|
||||||
|
label: 25 Gbps
|
||||||
|
- name: 40g
|
||||||
|
label: 40 Gbps
|
||||||
|
- name: 100g
|
||||||
|
label: 100 Gbps
|
||||||
|
description: "Interface speed"
|
||||||
|
|
||||||
|
# Layer 2 Attributes
|
||||||
|
- name: switchport_mode
|
||||||
|
kind: Dropdown
|
||||||
|
optional: true
|
||||||
|
choices:
|
||||||
|
- name: access
|
||||||
|
label: Access
|
||||||
|
- name: trunk
|
||||||
|
label: Trunk
|
||||||
|
- name: routed
|
||||||
|
label: Routed (no switchport)
|
||||||
|
description: "Switchport mode"
|
||||||
|
|
||||||
|
- name: trunk_groups
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Trunk groups (comma-separated)"
|
||||||
|
|
||||||
|
# Layer 3 Attributes
|
||||||
|
- name: ip_unnumbered
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: false
|
||||||
|
description: "Use IP unnumbered"
|
||||||
|
|
||||||
|
# Port-Channel Attributes
|
||||||
|
- name: channel_id
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "Port-channel ID"
|
||||||
|
|
||||||
|
- name: lacp_mode
|
||||||
|
kind: Dropdown
|
||||||
|
optional: true
|
||||||
|
choices:
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
- name: passive
|
||||||
|
label: Passive
|
||||||
|
- name: on
|
||||||
|
label: On (no LACP)
|
||||||
|
description: "LACP mode for port-channel"
|
||||||
|
|
||||||
|
# Loopback Attributes
|
||||||
|
- name: loopback_id
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "Loopback interface ID (0, 1, etc.)"
|
||||||
|
|
||||||
|
- name: loopback_purpose
|
||||||
|
kind: Dropdown
|
||||||
|
optional: true
|
||||||
|
choices:
|
||||||
|
- name: router_id
|
||||||
|
label: Router ID (Loopback0)
|
||||||
|
- name: vtep
|
||||||
|
label: VTEP (Loopback1)
|
||||||
|
- name: other
|
||||||
|
label: Other
|
||||||
|
description: "Loopback purpose"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: device
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
description: "Parent device"
|
||||||
|
|
||||||
|
- name: ip_addresses
|
||||||
|
peer: IpamIPAddress
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "IP addresses assigned to interface"
|
||||||
|
|
||||||
|
- name: unnumbered_source
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Source interface for IP unnumbered"
|
||||||
|
|
||||||
|
- name: allowed_vlans
|
||||||
|
peer: NetworkVLAN
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "VLANs allowed on trunk"
|
||||||
|
|
||||||
|
- name: port_channel
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Parent port-channel"
|
||||||
|
|
||||||
|
- name: member_interfaces
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Member interfaces (for port-channel)"
|
||||||
|
|
||||||
|
- name: connected_to
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Remote interface connection"
|
||||||
|
|
||||||
|
- name: mlag_config
|
||||||
|
peer: NetworkMLAGInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Component
|
||||||
|
description: "MLAG interface configuration"
|
||||||
|
|
||||||
|
- name: bgp_sessions
|
||||||
|
peer: NetworkBGPNeighbor
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "BGP sessions on this interface"
|
||||||
|
|
||||||
|
- name: ospf_config
|
||||||
|
peer: NetworkOSPFInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Component
|
||||||
|
description: "OSPF interface configuration"
|
||||||
146
infrahub/schema/06_vlan_vrfs.yml
Normal file
146
infrahub/schema/06_vlan_vrfs.yml
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: VLAN
|
||||||
|
namespace: Network
|
||||||
|
label: "VLAN"
|
||||||
|
icon: "mdi:lan"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["vlan_id__value", "name__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.vlan_id__value, record.name__value])) }}"
|
||||||
|
order_by:
|
||||||
|
- vlan_id__value
|
||||||
|
attributes:
|
||||||
|
- name: vlan_id
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
description: "VLAN ID (1-4094)"
|
||||||
|
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
description: "VLAN name"
|
||||||
|
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "VLAN description"
|
||||||
|
|
||||||
|
- name: trunk_groups
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Trunk groups (comma-separated, e.g., MLAGPEER)"
|
||||||
|
|
||||||
|
- name: status
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "active"
|
||||||
|
choices:
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
- name: suspended
|
||||||
|
label: Suspended
|
||||||
|
description: "VLAN status"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: devices
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Devices with this VLAN"
|
||||||
|
|
||||||
|
- name: interfaces
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Interfaces with this VLAN"
|
||||||
|
|
||||||
|
- name: svi
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "SVI interface for this VLAN"
|
||||||
|
|
||||||
|
- name: vrf
|
||||||
|
peer: NetworkVRF
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "VRF for this VLAN"
|
||||||
|
|
||||||
|
- name: vxlan_tunnel
|
||||||
|
peer: NetworkVXLANTunnel
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "VXLAN tunnel mapping"
|
||||||
|
|
||||||
|
- name: VRF
|
||||||
|
namespace: Network
|
||||||
|
label: "VRF"
|
||||||
|
icon: "mdi:router-network"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["name__value"]
|
||||||
|
display_label: "{{ record.name__value }}"
|
||||||
|
order_by:
|
||||||
|
- name__value
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "VRF name (e.g., default, tenant1)"
|
||||||
|
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "VRF description"
|
||||||
|
|
||||||
|
- name: route_distinguisher
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Route Distinguisher (e.g., 65001:100)"
|
||||||
|
|
||||||
|
- name: rt_import
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Route Target Import (comma-separated)"
|
||||||
|
|
||||||
|
- name: rt_export
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Route Target Export (comma-separated)"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: devices
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Devices with this VRF"
|
||||||
|
|
||||||
|
- name: interfaces
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Interfaces in this VRF"
|
||||||
|
|
||||||
|
- name: ip_prefixes
|
||||||
|
peer: IpamIPPrefix
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "IP prefixes in this VRF"
|
||||||
|
|
||||||
|
- name: vlans
|
||||||
|
peer: NetworkVLAN
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "VLANs in this VRF"
|
||||||
290
infrahub/schema/07_bgp.yml
Normal file
290
infrahub/schema/07_bgp.yml
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: BGPConfig
|
||||||
|
namespace: Network
|
||||||
|
label: "BGP Configuration"
|
||||||
|
icon: "mdi:routes"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["device__hostname__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.device__hostname__value, record.asn__value])) }}"
|
||||||
|
order_by:
|
||||||
|
- device__hostname__value
|
||||||
|
attributes:
|
||||||
|
- name: asn
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
description: "BGP AS Number"
|
||||||
|
|
||||||
|
- name: router_id
|
||||||
|
kind: IPHost
|
||||||
|
optional: false
|
||||||
|
description: "BGP Router ID (usually Loopback0)"
|
||||||
|
|
||||||
|
- name: maximum_paths
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 3
|
||||||
|
description: "Maximum paths for ECMP"
|
||||||
|
|
||||||
|
- name: distance_external
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 20
|
||||||
|
description: "Administrative distance for eBGP routes"
|
||||||
|
|
||||||
|
- name: distance_internal
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 200
|
||||||
|
description: "Administrative distance for iBGP routes"
|
||||||
|
|
||||||
|
- name: default_ipv4_unicast
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: false
|
||||||
|
description: "Enable default IPv4 unicast address family"
|
||||||
|
|
||||||
|
- name: ebgp_admin_distance
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 200
|
||||||
|
description: "eBGP admin distance override"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: device
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
description: "Parent device"
|
||||||
|
|
||||||
|
- name: peer_groups
|
||||||
|
peer: NetworkBGPPeerGroup
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "BGP peer groups"
|
||||||
|
|
||||||
|
- name: neighbors
|
||||||
|
peer: NetworkBGPNeighbor
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "BGP neighbors"
|
||||||
|
|
||||||
|
- name: address_families
|
||||||
|
peer: NetworkBGPAddressFamily
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "BGP address families"
|
||||||
|
|
||||||
|
- name: route_maps
|
||||||
|
peer: NetworkRouteMap
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Route maps used in BGP"
|
||||||
|
|
||||||
|
- name: prefix_lists
|
||||||
|
peer: NetworkPrefixList
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Prefix lists used in BGP"
|
||||||
|
|
||||||
|
- name: BGPPeerGroup
|
||||||
|
namespace: Network
|
||||||
|
label: "BGP Peer Group"
|
||||||
|
icon: "mdi:account-group"
|
||||||
|
include_in_menu: false
|
||||||
|
human_friendly_id: ["bgp_config__device__hostname__value", "name__value"]
|
||||||
|
display_label: "{{ record.name__value }}"
|
||||||
|
order_by:
|
||||||
|
- name__value
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
description: "Peer group name (e.g., SPINE_Underlay)"
|
||||||
|
|
||||||
|
- name: remote_asn
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "Remote AS number (for eBGP)"
|
||||||
|
|
||||||
|
- name: send_community
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: true
|
||||||
|
description: "Send community attributes"
|
||||||
|
|
||||||
|
- name: maximum_routes
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 12000
|
||||||
|
description: "Maximum routes from peers"
|
||||||
|
|
||||||
|
- name: peer_type
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "ebgp"
|
||||||
|
choices:
|
||||||
|
- name: ebgp
|
||||||
|
label: eBGP
|
||||||
|
- name: ibgp
|
||||||
|
label: iBGP
|
||||||
|
description: "Peer type"
|
||||||
|
|
||||||
|
- name: next_hop_self
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: false
|
||||||
|
description: "Set next-hop self for routes"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: bgp_config
|
||||||
|
peer: NetworkBGPConfig
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
|
||||||
|
- name: update_source
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Update source interface"
|
||||||
|
|
||||||
|
- name: neighbors
|
||||||
|
peer: NetworkBGPNeighbor
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Neighbors in this peer group"
|
||||||
|
|
||||||
|
- name: BGPNeighbor
|
||||||
|
namespace: Network
|
||||||
|
label: "BGP Neighbor"
|
||||||
|
icon: "mdi:account-network"
|
||||||
|
include_in_menu: false
|
||||||
|
human_friendly_id: ["bgp_config__device__hostname__value", "neighbor_ip__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.neighbor_ip__value, record.description__value])) }}"
|
||||||
|
order_by:
|
||||||
|
- neighbor_ip__value
|
||||||
|
attributes:
|
||||||
|
- name: neighbor_ip
|
||||||
|
kind: IPHost
|
||||||
|
optional: false
|
||||||
|
description: "Neighbor IP address"
|
||||||
|
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Neighbor description"
|
||||||
|
|
||||||
|
- name: enabled
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: true
|
||||||
|
description: "Neighbor enabled"
|
||||||
|
|
||||||
|
- name: peer_type
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "ebgp"
|
||||||
|
choices:
|
||||||
|
- name: ebgp
|
||||||
|
label: eBGP
|
||||||
|
- name: ibgp
|
||||||
|
label: iBGP
|
||||||
|
description: "Peer type"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: bgp_config
|
||||||
|
peer: NetworkBGPConfig
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
|
||||||
|
- name: peer_group
|
||||||
|
peer: NetworkBGPPeerGroup
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Peer group membership"
|
||||||
|
|
||||||
|
- name: local_interface
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Local interface for session"
|
||||||
|
|
||||||
|
- name: remote_device
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Remote device (if known)"
|
||||||
|
|
||||||
|
- name: BGPAddressFamily
|
||||||
|
namespace: Network
|
||||||
|
label: "BGP Address Family"
|
||||||
|
icon: "mdi:family-tree"
|
||||||
|
include_in_menu: false
|
||||||
|
human_friendly_id: ["bgp_config__device__hostname__value", "afi__value", "safi__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.afi__value, record.safi__value])) }}"
|
||||||
|
attributes:
|
||||||
|
- name: afi
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
choices:
|
||||||
|
- name: ipv4
|
||||||
|
label: IPv4
|
||||||
|
- name: ipv6
|
||||||
|
label: IPv6
|
||||||
|
- name: l2vpn
|
||||||
|
label: L2VPN
|
||||||
|
description: "Address Family Identifier"
|
||||||
|
|
||||||
|
- name: safi
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
choices:
|
||||||
|
- name: unicast
|
||||||
|
label: Unicast
|
||||||
|
- name: multicast
|
||||||
|
label: Multicast
|
||||||
|
- name: evpn
|
||||||
|
label: EVPN
|
||||||
|
description: "Sub-Address Family Identifier"
|
||||||
|
|
||||||
|
- name: activated
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: true
|
||||||
|
description: "Address family activated"
|
||||||
|
|
||||||
|
- name: redistribute_connected
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: false
|
||||||
|
description: "Redistribute connected routes"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: bgp_config
|
||||||
|
peer: NetworkBGPConfig
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
|
||||||
|
- name: route_map
|
||||||
|
peer: NetworkRouteMap
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Route map for redistribution"
|
||||||
151
infrahub/schema/08_mlag_evpn_vxlan.yml
Normal file
151
infrahub/schema/08_mlag_evpn_vxlan.yml
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: MLAGDomain
|
||||||
|
namespace: Network
|
||||||
|
label: "MLAG Domain"
|
||||||
|
icon: "mdi:link-variant"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["domain_id__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.domain_id__value, record.status__value])) }}"
|
||||||
|
order_by:
|
||||||
|
- domain_id__value
|
||||||
|
attributes:
|
||||||
|
- name: domain_id
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "MLAG domain identifier (e.g., MLAG-leaf1-2)"
|
||||||
|
|
||||||
|
- name: local_interface
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
default_value: "Vlan4094"
|
||||||
|
description: "Local interface for MLAG peer link"
|
||||||
|
|
||||||
|
- name: peer_interface
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
default_value: "Vlan4094"
|
||||||
|
description: "Peer interface for MLAG peer link"
|
||||||
|
|
||||||
|
- name: peer_address
|
||||||
|
kind: IPHost
|
||||||
|
optional: false
|
||||||
|
description: "Peer IP address for MLAG link"
|
||||||
|
|
||||||
|
- name: status
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "active"
|
||||||
|
choices:
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
- name: inactive
|
||||||
|
label: Inactive
|
||||||
|
description: "MLAG domain status"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: devices
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Devices in this MLAG domain"
|
||||||
|
|
||||||
|
- name: interfaces
|
||||||
|
peer: NetworkMLAGInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "MLAG-enabled interfaces"
|
||||||
|
|
||||||
|
- name: MLAGInterface
|
||||||
|
namespace: Network
|
||||||
|
label: "MLAG Interface"
|
||||||
|
icon: "mdi:ethernet-plus"
|
||||||
|
include_in_menu: false
|
||||||
|
human_friendly_id: ["interface__device__hostname__value", "interface__name__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.interface__device__hostname__value, record.interface__name__value])) }}"
|
||||||
|
attributes:
|
||||||
|
- name: mlag_id
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
description: "MLAG interface ID"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: mlag_domain
|
||||||
|
peer: NetworkMLAGDomain
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
|
||||||
|
- name: interface
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Physical interface"
|
||||||
|
|
||||||
|
- name: EVPNConfig
|
||||||
|
namespace: Network
|
||||||
|
label: "EVPN Configuration"
|
||||||
|
icon: "mdi:wan"
|
||||||
|
include_in_menu: false
|
||||||
|
human_friendly_id: ["device__hostname__value"]
|
||||||
|
display_label: "{{ record.device__hostname__value }}"
|
||||||
|
attributes:
|
||||||
|
- name: vni_auto
|
||||||
|
kind: Boolean
|
||||||
|
optional: false
|
||||||
|
default_value: true
|
||||||
|
description: "Automatically generate VNIs"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: device
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
|
||||||
|
- name: VXLANTunnel
|
||||||
|
namespace: Network
|
||||||
|
label: "VXLAN Tunnel"
|
||||||
|
icon: "mdi:tunnel"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["name__value"]
|
||||||
|
display_label: "{{ record.name__value }}"
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
default_value: "Vxlan1"
|
||||||
|
description: "VXLAN tunnel interface name"
|
||||||
|
|
||||||
|
- name: source_ip
|
||||||
|
kind: IPHost
|
||||||
|
optional: false
|
||||||
|
description: "Source IP for VXLAN tunnel (Loopback1)"
|
||||||
|
|
||||||
|
- name: udp_port
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 4789
|
||||||
|
description: "VXLAN UDP port"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: device
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
|
||||||
|
- name: vlans
|
||||||
|
peer: NetworkVLAN
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "VLANs mapped to this VXLAN tunnel"
|
||||||
239
infrahub/schema/09_routing_policies.yml
Normal file
239
infrahub/schema/09_routing_policies.yml
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: RouteMap
|
||||||
|
namespace: Network
|
||||||
|
label: "Route Map"
|
||||||
|
icon: "mdi:map-marker-path"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["name__value"]
|
||||||
|
display_label: "{{ record.name__value }}"
|
||||||
|
order_by:
|
||||||
|
- name__value
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "Route map name (e.g., LOOPBACK)"
|
||||||
|
|
||||||
|
- name: sequence
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 10
|
||||||
|
description: "Sequence number"
|
||||||
|
|
||||||
|
- name: action
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "permit"
|
||||||
|
choices:
|
||||||
|
- name: permit
|
||||||
|
label: Permit
|
||||||
|
- name: deny
|
||||||
|
label: Deny
|
||||||
|
description: "Action (permit/deny)"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: devices
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Devices using this route map"
|
||||||
|
|
||||||
|
- name: prefix_lists
|
||||||
|
peer: NetworkPrefixList
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Prefix lists matched by this route map"
|
||||||
|
|
||||||
|
- name: PrefixList
|
||||||
|
namespace: Network
|
||||||
|
label: "Prefix List"
|
||||||
|
icon: "mdi:format-list-numbered"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["name__value"]
|
||||||
|
display_label: "{{ record.name__value }}"
|
||||||
|
order_by:
|
||||||
|
- name__value
|
||||||
|
attributes:
|
||||||
|
- name: name
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "Prefix list name (e.g., LOOPBACK)"
|
||||||
|
|
||||||
|
- name: sequence
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 10
|
||||||
|
description: "Sequence number"
|
||||||
|
|
||||||
|
- name: action
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "permit"
|
||||||
|
choices:
|
||||||
|
- name: permit
|
||||||
|
label: Permit
|
||||||
|
- name: deny
|
||||||
|
label: Deny
|
||||||
|
description: "Action (permit/deny)"
|
||||||
|
|
||||||
|
- name: prefix
|
||||||
|
kind: IPNetwork
|
||||||
|
optional: false
|
||||||
|
description: "IP prefix to match"
|
||||||
|
|
||||||
|
- name: match_type
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "exact"
|
||||||
|
choices:
|
||||||
|
- name: exact
|
||||||
|
label: Exact Match
|
||||||
|
- name: ge
|
||||||
|
label: Greater or Equal
|
||||||
|
- name: le
|
||||||
|
label: Less or Equal
|
||||||
|
description: "Match type"
|
||||||
|
|
||||||
|
- name: greater_equal
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "Greater or equal prefix length"
|
||||||
|
|
||||||
|
- name: less_equal
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "Less or equal prefix length"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: devices
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Devices using this prefix list"
|
||||||
|
|
||||||
|
- name: OSPFConfig
|
||||||
|
namespace: Network
|
||||||
|
label: "OSPF Configuration"
|
||||||
|
icon: "mdi:router"
|
||||||
|
include_in_menu: false
|
||||||
|
human_friendly_id: ["device__hostname__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.device__hostname__value, record.process_id__value])) }}"
|
||||||
|
attributes:
|
||||||
|
- name: process_id
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 100
|
||||||
|
description: "OSPF process ID"
|
||||||
|
|
||||||
|
- name: router_id
|
||||||
|
kind: IPHost
|
||||||
|
optional: false
|
||||||
|
description: "OSPF router ID"
|
||||||
|
|
||||||
|
- name: max_paths
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 3
|
||||||
|
description: "Maximum paths for ECMP"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: device
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
|
||||||
|
- name: areas
|
||||||
|
peer: NetworkOSPFArea
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "OSPF areas"
|
||||||
|
|
||||||
|
- name: OSPFArea
|
||||||
|
namespace: Network
|
||||||
|
label: "OSPF Area"
|
||||||
|
icon: "mdi:circle-outline"
|
||||||
|
include_in_menu: false
|
||||||
|
human_friendly_id: ["ospf_config__device__hostname__value", "area_id__value"]
|
||||||
|
display_label: "{{ record.area_id__value }}"
|
||||||
|
attributes:
|
||||||
|
- name: area_id
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
default_value: "0.0.0.0"
|
||||||
|
description: "OSPF area ID (e.g., 0.0.0.0)"
|
||||||
|
|
||||||
|
- name: area_type
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "standard"
|
||||||
|
choices:
|
||||||
|
- name: standard
|
||||||
|
label: Standard
|
||||||
|
- name: stub
|
||||||
|
label: Stub
|
||||||
|
- name: nssa
|
||||||
|
label: NSSA
|
||||||
|
description: "Area type"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: ospf_config
|
||||||
|
peer: NetworkOSPFConfig
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
|
||||||
|
- name: interfaces
|
||||||
|
peer: NetworkOSPFInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "Interfaces in this area"
|
||||||
|
|
||||||
|
- name: OSPFInterface
|
||||||
|
namespace: Network
|
||||||
|
label: "OSPF Interface"
|
||||||
|
icon: "mdi:ethernet"
|
||||||
|
include_in_menu: false
|
||||||
|
human_friendly_id: ["interface__device__hostname__value", "interface__name__value"]
|
||||||
|
display_label: "{{ record.interface__name__value }}"
|
||||||
|
attributes:
|
||||||
|
- name: network_type
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "point-to-point"
|
||||||
|
choices:
|
||||||
|
- name: point-to-point
|
||||||
|
label: Point-to-Point
|
||||||
|
- name: broadcast
|
||||||
|
label: Broadcast
|
||||||
|
description: "OSPF network type"
|
||||||
|
|
||||||
|
- name: cost
|
||||||
|
kind: Number
|
||||||
|
optional: true
|
||||||
|
description: "OSPF cost"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: area
|
||||||
|
peer: NetworkOSPFArea
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
|
||||||
|
- name: interface
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Physical interface"
|
||||||
219
infrahub/schema/10_dci.yml
Normal file
219
infrahub/schema/10_dci.yml
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
||||||
|
---
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
nodes:
|
||||||
|
- name: DCISwitch
|
||||||
|
namespace: Network
|
||||||
|
label: "DCI Interconnect Switch"
|
||||||
|
icon: "mdi:transit-connection-variant"
|
||||||
|
include_in_menu: true
|
||||||
|
human_friendly_id: ["hostname__value"]
|
||||||
|
display_label: "{{ record.hostname__value }}"
|
||||||
|
order_by:
|
||||||
|
- hostname__value
|
||||||
|
description: "DCI switch connects multiple datacenters - NOT auto-generated, manually configured"
|
||||||
|
attributes:
|
||||||
|
- name: hostname
|
||||||
|
kind: Text
|
||||||
|
unique: true
|
||||||
|
optional: false
|
||||||
|
description: "DCI switch hostname (e.g., DCI)"
|
||||||
|
|
||||||
|
- name: description
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
default_value: "DCI Interconnect Switch"
|
||||||
|
description: "DCI switch description"
|
||||||
|
|
||||||
|
- name: platform
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
default_value: "cEOS"
|
||||||
|
description: "Device platform"
|
||||||
|
|
||||||
|
- name: eos_version
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "EOS software version"
|
||||||
|
|
||||||
|
- name: serial_number
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
unique: true
|
||||||
|
description: "Device serial number"
|
||||||
|
|
||||||
|
- name: management_ip
|
||||||
|
kind: IPHost
|
||||||
|
optional: true
|
||||||
|
description: "Management IP address (e.g., 10.255.0.253)"
|
||||||
|
|
||||||
|
- name: loopback0_ip
|
||||||
|
kind: IPHost
|
||||||
|
optional: false
|
||||||
|
description: "Loopback0 IP for BGP router-id (e.g., 10.253.0.1/32)"
|
||||||
|
|
||||||
|
- name: status
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "active"
|
||||||
|
choices:
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
color: "#7fbf7f"
|
||||||
|
- name: planned
|
||||||
|
label: Planned
|
||||||
|
color: "#ffd966"
|
||||||
|
- name: maintenance
|
||||||
|
label: Maintenance
|
||||||
|
color: "#ff9999"
|
||||||
|
- name: decommissioned
|
||||||
|
label: Decommissioned
|
||||||
|
color: "#cccccc"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: organization
|
||||||
|
peer: CoreOrganization
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Parent organization"
|
||||||
|
|
||||||
|
- name: connected_datacenters
|
||||||
|
peer: InfraDatacenter
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Generic
|
||||||
|
description: "Datacenters interconnected by this DCI switch"
|
||||||
|
|
||||||
|
- name: interfaces
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "DCI switch interfaces"
|
||||||
|
|
||||||
|
- name: bgp_config
|
||||||
|
peer: NetworkBGPConfig
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Component
|
||||||
|
description: "BGP configuration for DCI"
|
||||||
|
|
||||||
|
- name: dci_connections
|
||||||
|
peer: NetworkDCIConnection
|
||||||
|
optional: true
|
||||||
|
cardinality: many
|
||||||
|
kind: Component
|
||||||
|
description: "DCI connections to border leafs"
|
||||||
|
|
||||||
|
- name: DCIConnection
|
||||||
|
namespace: Network
|
||||||
|
label: "DCI Connection"
|
||||||
|
icon: "mdi:cable-data"
|
||||||
|
include_in_menu: true
|
||||||
|
menu_placement: "NetworkDCISwitch"
|
||||||
|
human_friendly_id: ["dci_switch__hostname__value", "border_leaf__hostname__value"]
|
||||||
|
display_label: "{{ ' - '.join(filter(None, [record.dci_switch__hostname__value, record.border_leaf__hostname__value, record.status__value])) }}"
|
||||||
|
order_by:
|
||||||
|
- dci_switch__hostname__value
|
||||||
|
description: "Represents a P2P connection between DCI switch and a border leaf"
|
||||||
|
attributes:
|
||||||
|
- name: connection_name
|
||||||
|
kind: Text
|
||||||
|
optional: true
|
||||||
|
description: "Connection identifier (e.g., DCI-to-borderleaf1-DC1)"
|
||||||
|
|
||||||
|
- name: status
|
||||||
|
kind: Dropdown
|
||||||
|
optional: false
|
||||||
|
default_value: "shutdown"
|
||||||
|
choices:
|
||||||
|
- name: active
|
||||||
|
label: Active
|
||||||
|
description: "Connection is enabled and operational"
|
||||||
|
color: "#7fbf7f"
|
||||||
|
- name: shutdown
|
||||||
|
label: Shutdown
|
||||||
|
description: "Connection administratively disabled"
|
||||||
|
color: "#cccccc"
|
||||||
|
- name: maintenance
|
||||||
|
label: Maintenance
|
||||||
|
description: "Connection under maintenance"
|
||||||
|
color: "#ff9999"
|
||||||
|
description: "Connection operational status (shutdown until dci_enabled=true)"
|
||||||
|
|
||||||
|
- name: dci_interface_name
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
description: "DCI switch interface (e.g., Ethernet1)"
|
||||||
|
|
||||||
|
- name: border_interface_name
|
||||||
|
kind: Text
|
||||||
|
optional: false
|
||||||
|
default_value: "Ethernet12"
|
||||||
|
description: "Border leaf interface (always Ethernet12)"
|
||||||
|
|
||||||
|
- name: dci_ip
|
||||||
|
kind: IPHost
|
||||||
|
optional: false
|
||||||
|
description: "DCI side IP address (e.g., 10.254.0.1/31)"
|
||||||
|
|
||||||
|
- name: border_ip
|
||||||
|
kind: IPHost
|
||||||
|
optional: false
|
||||||
|
description: "Border leaf side IP address (e.g., 10.254.0.0/31)"
|
||||||
|
|
||||||
|
- name: subnet
|
||||||
|
kind: IPNetwork
|
||||||
|
optional: false
|
||||||
|
description: "P2P subnet (e.g., 10.254.0.0/31)"
|
||||||
|
|
||||||
|
- name: mtu
|
||||||
|
kind: Number
|
||||||
|
optional: false
|
||||||
|
default_value: 9214
|
||||||
|
description: "Interface MTU"
|
||||||
|
|
||||||
|
relationships:
|
||||||
|
- name: dci_switch
|
||||||
|
peer: NetworkDCISwitch
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Parent
|
||||||
|
description: "Parent DCI switch"
|
||||||
|
|
||||||
|
- name: border_leaf
|
||||||
|
peer: NetworkDevice
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Connected border leaf device"
|
||||||
|
|
||||||
|
- name: datacenter
|
||||||
|
peer: InfraDatacenter
|
||||||
|
optional: false
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Datacenter of the border leaf"
|
||||||
|
|
||||||
|
- name: dci_interface
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "DCI switch interface object"
|
||||||
|
|
||||||
|
- name: border_interface
|
||||||
|
peer: NetworkInterface
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "Border leaf interface object (eth12)"
|
||||||
|
|
||||||
|
- name: bgp_session
|
||||||
|
peer: NetworkBGPNeighbor
|
||||||
|
optional: true
|
||||||
|
cardinality: one
|
||||||
|
kind: Attribute
|
||||||
|
description: "BGP session for this connection"
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
# yaml-language-server $schema=https://schema.infrahub.app/infrahub/schema/latest.json
|
|
||||||
version: "1.0"
|
|
||||||
nodes:
|
|
||||||
- name: Device
|
|
||||||
namespace: Infra
|
|
||||||
Reference in New Issue
Block a user