# 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
bays=2, spines=3] Site --> DC DC --> Spines[Spine Layer
spine1-3-DC1] DC --> Leafs[Leaf Layer
leaf1-4-DC1] DC --> Borders[Border Layer
borderleaf1-2-DC1] DC --> Bays[Bay Layer
bay1-2] Bays --> Bay1[Bay 1] Bays --> Bay2[Bay 2] Bay1 --> Access1[access1-DC1] Bay2 --> Access2[access2-DC1] Access1 --> LeafPair1[Leaf Pair 1
leaf1-2-DC1] Access2 --> LeafPair2[Leaf Pair 2
leaf3-4-DC1] LeafPair1 --> Spines LeafPair2 --> Spines Borders --> Spines ``` ### Detailed Device-Level Diagram ```mermaid graph LR subgraph DC1 S1[spine1-DC1
10.1.0.11] S2[spine2-DC1
10.1.0.12] S3[spine3-DC1
10.1.0.13] L1[leaf1-DC1
10.1.0.21
VTEP: 10.1.1.21] L2[leaf2-DC1
10.1.0.22
VTEP: 10.1.1.21] L3[leaf3-DC1
10.1.0.23
VTEP: 10.1.1.23] L4[leaf4-DC1
10.1.0.24
VTEP: 10.1.1.23] A1[access1-DC1
Bay 1] A2[access2-DC1
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!