Lesson 1 of 6

IaC Foundation for AIOps

Objective

In this lesson you will learn why Infrastructure as Code (IaC) is the foundation for AIOps. We focus on version control and reproducibility: storing device configuration as code (templates), tracking changes with Git, and reproducing a known-good configuration on multiple devices. This matters in production because IaC eliminates manual CLI drift, enables automated testing, and gives traceable, reversible changes — essential for stable, observable networks used by automation and AI-driven operations.

Real-world scenario: In a campus running hundreds of access switches and routers, operations needs to roll out a baseline management configuration and later reproduce it for new devices or during recovery. IaC + version control allows safe, auditable, and repeatable deployments, which are prerequisites for AIOps systems that detect and auto-remediate drift.


Topology & Device Table

ASCII topology (management-plane only — exact IPs shown on management interfaces):

Network Topology Diagram

Device Table

DeviceInterfaceIP AddressSubnet MaskRole
R1GigabitEthernet0/010.0.0.1255.255.255.0Router (baseline)
R2GigabitEthernet0/010.0.0.2255.255.255.0Router (reprovision)
SW1VLAN100 (mgmt)10.0.0.10255.255.255.0L2 switch, management VLAN
Git Servereth010.0.0.100255.255.255.0Git repository (lab.nhprep.com)
Host Aeth010.0.0.50255.255.255.0Test host

Important: This lesson focuses on management-plane configuration and IaC workflows. The commands below are examples of the Git/IaC workflow and IOS configuration used to demonstrate reproducibility.


Key Concepts (Theory + Practical)

  • Infrastructure as Code (IaC): Represent device configuration as plain-text files (templates). Theory: text files are versionable, diffable, and can be validated and tested. In production: templates are used to generate many device configs and to drive automation tools for deployment.
  • Version control (Git): Tracks who changed what and when; supports branching for testing. Packet/behavior note: Git operations are out-of-band (over SSH/HTTPS) and do not change device runtime until you apply the configuration to the device.
  • Reproducibility & Idempotency: Applying the same configuration template to different devices or reapplying it should result in the same intended state. This is required for automated remediation where AIOps systems rely on determinism.
  • Separation of concerns: Keep base templates (global params) separate from device-specific variables (IP, hostname). This enables safe reuse and prevents accidental device misconfiguration in production.
  • Audit trail + Rollback: Commits are the single source of truth. When a config causes problems, you can revert to a previous commit, validate, and reapply quickly — an essential operational control in production environments.

Step-by-step configuration

Step 1: Configure management interfaces on routers (baseline device R1)

What we are doing: Configure the management IP and hostname on R1 so it can be reached by the Git server and by operators. This establishes the reproducible management plane that IaC will target.

enable
configure terminal
hostname R1
interface GigabitEthernet0/0
 description Management interface to VLAN100
 ip address 10.0.0.1 255.255.255.0
 no shutdown
exit
ip domain-name lab.nhprep.com
line vty 0 4
 login local
 transport input ssh
exit
username admin privilege 15 secret Lab@123
end
write memory

What just happened: The commands set the device hostname to R1, assign 10.0.0.1/24 to Gi0/0, enable SSH access with a local account (admin), and save the running configuration to NVRAM. SSH and domain name are required for secure IaC tools to connect out-of-band. The interface change causes the router to send ARP requests on VLAN100; once ARP resolves, the device is reachable for automation.

Real-world note: In production, management interfaces are restricted to a dedicated management VLAN and protected by ACLs — never expose router management directly to user VLANs.

Verify:

show ip interface brief

Expected output:

Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet0/0     10.0.0.1        YES manual up                    up
Loopback0              unassigned      YES unset  administratively down down

Step 2: Initialize a Git repository on lab.nhprep.com and create baseline config template

What we are doing: Create a Git repository to store the baseline device configuration as code. This gives us history, diffs, and the ability to reproduce configurations.

# On the Git server (lab.nhprep.com), initialize a repo and add a baseline template
mkdir -p /srv/git/iac
cd /srv/git/iac
git init --bare iac-config.git
# Create a working clone and add a baseline template file (local admin workstation)
git clone git@lab.nhprep.com:/srv/git/iac/iac-config.git
cd iac-config
cat > templates/R1_base.cfg <<'EOF'
hostname {{ hostname }}
interface GigabitEthernet0/0
 description Management interface to VLAN100
 ip address {{ mgmt_ip }} 255.255.255.0
 no shutdown
ip domain-name lab.nhprep.com
username admin privilege 15 secret Lab@123
EOF
git add templates/R1_base.cfg
git commit -m "Add baseline router template"
git push origin main

What just happened: We created a bare Git repository that serves as the canonical store, cloned it locally, added a template file (with placeholder variables), committed, and pushed. The template contains variables ({{ hostname }}, {{ mgmt_ip }}) that separate device-specific values from the template logic — enabling reproducible instantiation for multiple routers.

Real-world note: In production, Git servers are hardened and use access control; templates are stored in well-defined directories and are validated by CI pipelines before deployment.

Verify:

# Show git log to confirm commit
git --no-pager log --oneline --decorate --all

Expected output:

a1b2c3d Add baseline router template


<div class="topology-diagram">
<img src="data:image/svg+xml;base64,PD9wbGFudHVtbCAxLjIwMjYuMT8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBjb250ZW50U3R5bGVUeXBlPSJ0ZXh0L2NzcyIgZGF0YS1kaWFncmFtLXR5cGU9Ik5XRElBRyIgaGVpZ2h0PSIxNTRweCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSIgc3R5bGU9IndpZHRoOjQwMHB4O2hlaWdodDoxNTRweDtiYWNrZ3JvdW5kOiNGRkZGRkY7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA0MDAgMTU0IiB3aWR0aD0iNDAwcHgiIHpvb21BbmRQYW49Im1hZ25pZnkiPjxkZWZzLz48Zz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI3OS4wNDg4IiB4PSI1IiB5PSIxNi4xMzg3Ij5NYW5hZ2VtZW50PC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjY4LjkyOTciIHg9IjE1LjExOTEiIHk9IjMwLjEwNzQiPjEwLjAuMC4wLzI0PC90ZXh0PjxyZWN0IGZpbGw9IiNFMkUyRjAiIGhlaWdodD0iNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIgd2lkdGg9IjMwMy44Mzc5IiB4PSI4OS4wNDg4IiB5PSIxNi40Njg4Ii8+PHBhdGggZD0iTTEzNy42NTIzLDIxLjQ2ODggTDEzNy42NTIzLDY0LjI3MzQiIGZpbGw9Im5vbmUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1Mi40ODEiIHg9IjExMS40MTE5IiB5PSIzNy43NzY5Ij4xMC4wLjAuMTA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMjUuMDUwOCIgeD0iMTExLjQxMTkiIHk9IjUwLjU4MTUiPmV0aDA8L3RleHQ+PHBhdGggZD0iTTI0MC42MDA2LDIxLjQ2ODggTDI0MC42MDA2LDY0LjI3MzQiIGZpbGw9Im5vbmUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1Mi40ODEiIHg9IjIxNC4zNjAxIiB5PSIzNy43NzY5Ij4xMC4wLjAuMjA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMjUuMDUwOCIgeD0iMjE0LjM2MDEiIHk9IjUwLjU4MTUiPmV0aDA8L3RleHQ+PHBhdGggZD0iTTM0NS45MTYsMjEuNDY4OCBMMzQ1LjkxNiw2NC4yNzM0IiBmaWxsPSJub25lIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDUuNDgyNCIgeD0iMzIzLjE3NDgiIHk9IjM3Ljc3NjkiPjEwLjAuMC4xPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjM5LjcyNDYiIHg9IjMyMy4xNzQ4IiB5PSI1MC41ODE1Ij5tZ210MDwvdGV4dD48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9IjMzLjk2ODgiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjYzLjIwNyIgeD0iMTA0LjA0ODgiIHk9IjY0LjI3MzQiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI0My4yMDciIHg9IjExNC4wNDg4IiB5PSI4NS40MTIxIj5EZXZXUzwvdGV4dD48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9IjMzLjk2ODgiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjgyLjY4OTUiIHg9IjE5Ny4yNTU5IiB5PSI2NC4yNzM0Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNjIuNjg5NSIgeD0iMjA3LjI1NTkiIHk9Ijg1LjQxMjEiPkdpdF9TZXJ2ZXI8L3RleHQ+PHJlY3QgZmlsbD0iI0YxRjFGMSIgaGVpZ2h0PSIzMy45Njg4IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHdpZHRoPSI2Ny45NDE0IiB4PSIzMDkuOTQ1MyIgeT0iNjQuMjczNCIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjQ3Ljk0MTQiIHg9IjMxOS45NDUzIiB5PSI4NS40MTIxIj5Sb3V0ZXIxPC90ZXh0Pjw/cGxhbnR1bWwtc3JjIG9vakZvS25DTHdaY0tiMzhJb3FmcG9fQUxsMURwNGpDSnlyRHBJaTEyb2llOUFRYTVBS001b2xPQVlXUDZrWTFlUndIWUg5T3BZTXJCM25POEhmSllRNTEzRDMwMzBFYk02a21HbFZDYWxaV3JBQW9yMjlpZ2V0R0wwVmJidlFhNVhiWURKV2NCcFN6am1JZ2o5UWg1VzAwPz48L2c+PC9zdmc+" alt="Network Topology Diagram" style="max-width:100%;height:auto;background:#fff;padding:16px;border:1px solid #e5e7eb;border-radius:8px;" />
</div>

cisco
# Render template into device configs (example using simple variable substitution)
mkdir -p devices
cat > devices/R1.cfg <<'EOF'
hostname R1
interface GigabitEthernet0/0
 description Management interface to VLAN100
 ip address 10.0.0.1 255.255.255.0
 no shutdown
ip domain-name lab.nhprep.com
username admin privilege 15 secret Lab@123
EOF
git add devices/R1.cfg
git commit -m "Device config: R1 management baseline"
git push origin main

What just happened: The rendered device config is a concrete file that matches the actual running configuration we applied earlier. Committing it creates an auditable source of truth for R1’s intended configuration. This practice ensures the running device configuration can be compared against the committed desired state.

Real-world note: Rendering is typically done by templating engines (Jinja2, etc.) in CI pipelines; here we demonstrate the principle with direct file creation.

Verify:

git show --pretty=oneline --name-only HEAD

Expected output:

a1b2c3d Device config: R1 management baseline
devices/R1.cfg


<div class="topology-diagram">
<img src="data:image/svg+xml;base64,PD9wbGFudHVtbCAxLjIwMjYuMT8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBjb250ZW50U3R5bGVUeXBlPSJ0ZXh0L2NzcyIgZGF0YS1kaWFncmFtLXR5cGU9Ik5XRElBRyIgaGVpZ2h0PSIxNTRweCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSIgc3R5bGU9IndpZHRoOjQwMHB4O2hlaWdodDoxNTRweDtiYWNrZ3JvdW5kOiNGRkZGRkY7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA0MDAgMTU0IiB3aWR0aD0iNDAwcHgiIHpvb21BbmRQYW49Im1hZ25pZnkiPjxkZWZzLz48Zz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI3OS4wNDg4IiB4PSI1IiB5PSIxNi4xMzg3Ij5NYW5hZ2VtZW50PC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjY4LjkyOTciIHg9IjE1LjExOTEiIHk9IjMwLjEwNzQiPjEwLjAuMC4wLzI0PC90ZXh0PjxyZWN0IGZpbGw9IiNFMkUyRjAiIGhlaWdodD0iNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxOyIgd2lkdGg9IjMwMy44Mzc5IiB4PSI4OS4wNDg4IiB5PSIxNi40Njg4Ii8+PHBhdGggZD0iTTEzNy42NTIzLDIxLjQ2ODggTDEzNy42NTIzLDY0LjI3MzQiIGZpbGw9Im5vbmUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1Mi40ODEiIHg9IjExMS40MTE5IiB5PSIzNy43NzY5Ij4xMC4wLjAuMTA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMjUuMDUwOCIgeD0iMTExLjQxMTkiIHk9IjUwLjU4MTUiPmV0aDA8L3RleHQ+PHBhdGggZD0iTTI0MC42MDA2LDIxLjQ2ODggTDI0MC42MDA2LDY0LjI3MzQiIGZpbGw9Im5vbmUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MTsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1Mi40ODEiIHg9IjIxNC4zNjAxIiB5PSIzNy43NzY5Ij4xMC4wLjAuMjA8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMjUuMDUwOCIgeD0iMjE0LjM2MDEiIHk9IjUwLjU4MTUiPmV0aDA8L3RleHQ+PHBhdGggZD0iTTM0NS45MTYsMjEuNDY4OCBMMzQ1LjkxNiw2NC4yNzM0IiBmaWxsPSJub25lIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjE7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNDUuNDgyNCIgeD0iMzIzLjE3NDgiIHk9IjM3Ljc3NjkiPjEwLjAuMC4xPC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjM5LjcyNDYiIHg9IjMyMy4xNzQ4IiB5PSI1MC41ODE1Ij5tZ210MDwvdGV4dD48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9IjMzLjk2ODgiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjYzLjIwNyIgeD0iMTA0LjA0ODgiIHk9IjY0LjI3MzQiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI0My4yMDciIHg9IjExNC4wNDg4IiB5PSI4NS40MTIxIj5EZXZXUzwvdGV4dD48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9IjMzLjk2ODgiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjgyLjY4OTUiIHg9IjE5Ny4yNTU5IiB5PSI2NC4yNzM0Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iNjIuNjg5NSIgeD0iMjA3LjI1NTkiIHk9Ijg1LjQxMjEiPkdpdF9TZXJ2ZXI8L3RleHQ+PHJlY3QgZmlsbD0iI0YxRjFGMSIgaGVpZ2h0PSIzMy45Njg4IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHdpZHRoPSI2Ny45NDE0IiB4PSIzMDkuOTQ1MyIgeT0iNjQuMjczNCIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjQ3Ljk0MTQiIHg9IjMxOS45NDUzIiB5PSI4NS40MTIxIj5Sb3V0ZXIxPC90ZXh0Pjw/cGxhbnR1bWwtc3JjIG9vakZvS25DTHdaY0tiMzhJb3FmcG9fQUxsMURwNGpDSnlyRHBJaTEyb2llOUFRYTVBS001b2xPQVlXUDZrWTFlUndIWUg5T3BZTXJCM25POEhmSllRNTEzRDMwMzBFYk02a21HbFZDYWxaV3JBQW9yMjlpZ2V0R0wwVmJidlFhNVhiWURKV2NCcFN6am1JZ2o5UWg1VzAwPz48L2c+PC9zdmc+" alt="Network Topology Diagram" style="max-width:100%;height:auto;background:#fff;padding:16px;border:1px solid #e5e7eb;border-radius:8px;" />
</div>

cisco
# On local admin host: create device config for R2 and copy to R2 via SSH/CLI
cat > devices/R2.cfg <<'EOF'
hostname R2
interface GigabitEthernet0/0
 description Management interface to VLAN100
 ip address 10.0.0.2 255.255.255.0
 no shutdown
ip domain-name lab.nhprep.com
username admin privilege 15 secret Lab@123
EOF
git add devices/R2.cfg
git commit -m "Device config: R2 management baseline"
git push origin main

# Apply to R2 (example applying via SSH + configuration paste)
ssh admin@10.0.0.2
enable
configure terminal
hostname R2
interface GigabitEthernet0/0
 description Management interface to VLAN100
 ip address 10.0.0.2 255.255.255.0
 no shutdown
exit
ip domain-name lab.nhprep.com
username admin privilege 15 secret Lab@123
end
write memory
exit

What just happened: We created and committed R2’s device config in Git, then applied it to R2 via an SSH CLI session. The same template-driven configuration produced a consistent baseline on R2. This manual application mimics what an automation tool (Ansible, Terraform provider) would do programmatically in production.

Real-world note: In production you'll automate the SSH/Netconf/REST apply with tools that support idempotency; manual SSH application is used here for clarity.

Verify:

# On R2, verify interface and hostname
show running-config

Expected output (excerpt showing relevant lines):

hostname R2
!
interface GigabitEthernet0/0
 description Management interface to VLAN100
 ip address 10.0.0.2 255.255.255.0
 no shutdown
!
ip domain-name lab.nhprep.com
username admin privilege 15 secret 5 $1$abcdefgh$abcdefghijklmno
!
end

Also verify interface state:

show ip interface brief

Expected output:

Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet0/0     10.0.0.2        YES manual up                    up
Loopback0              unassigned      YES unset  administratively down down

Step 5: Demonstrate reproducibility and rollback (clone and reapply)

What we are doing: Clone the Git repository to a fresh workspace to show how any operator or CI job can reproduce the same device configs; then show how to rollback a change by reverting a commit.

# Clone the canonical repo
git clone git@lab.nhprep.com:/srv/git/iac/iac-config.git reproducible-workspace
cd reproducible-workspace
ls -R

# Simulate an erroneous change and rollback
git checkout -b temp-change
sed -i 's/10.0.0.2/10.0.0.99/g' devices/R2.cfg
git commit -am "Temp change: wrong IP injected"
git push origin temp-change

# Rollback locally to main (revert the commit)
git checkout main
git revert HEAD --no-edit
git push origin main

What just happened: Cloning reproduces the repo contents anywhere. Introducing a bad change and then reverting demonstrates the rollback workflow: Git allows safe, auditable remediation. In a CI pipeline, a failed validation would prevent merging the bad commit to main, preventing incorrect configs from ever being applied.

Real-world note: Use branch protections on the main branch and automated validations to prevent bad configurations from reaching production devices.

Verify:

# Show git history to confirm revert
git --no-pager log --oneline --decorate --graph -n 5

Expected output:

f6e7d8c (HEAD -> main, origin/main) Revert "Temp change: wrong IP injected"
a1b2c3d Device config: R2 management baseline
9a8b7c6 Add baseline router template

Verification Checklist

  • Check 1: R1 management interface is up and reachable — verify with show ip interface brief on R1 and a successful ping from Git server to 10.0.0.1.
  • Check 2: Git repository contains baseline template and device configs — verify with git --no-pager log --oneline and git show HEAD:devices/R1.cfg.
  • Check 3: R2 was provisioned with the same template-derived config — verify with show running-config and show ip interface brief on R2.

Common Mistakes

SymptomCauseFix
Cannot SSH to router from Git serverManagement IP not configured or interface administratively downVerify show ip interface brief, ensure no shutdown on interface; check VLAN and switch port connectivity
Template variables not substituted (literal {{ hostname }})Template rendering step missed or improper templating toolEnsure templates are rendered before committing device-specific files; use CI or templating engine to apply variables
Incorrect file in Git used to provision deviceAdmin manually edited wrong branch or fileUse branch protections; verify the main branch contents and use git checkout to correct; run git log to inspect history
Changes applied to device but not committed to GitDrift between running-config and repository (no source-of-truth)Always commit intended configs before/after applying; implement pre-commit or CI checks to prevent drift

Key Takeaways

  • IaC is the prerequisite for AIOps: Representing network intent as code enables automated validation, auditing, and reproducibility required by AI-driven operations.
  • Version control (Git) provides an auditable single source of truth; commits and branches support safe experimentation and rollback.
  • Separate templates and device variables to achieve idempotent, reproducible provisioning across multiple devices.
  • In production, combine Git with CI pipelines and automation tools to validate and safely apply configurations; protect the main branch and use automated tests to prevent bad configurations from being deployed.

Final real-world insight: Treat your Git repository like the network’s "truth database" — every deployed change should be traceable to a commit. IaC reduces mean time to repair and is the foundation on which AIOps can deliver autonomous, reliable network operations.