Building a Private Local AIOps Assistant: Part 5 (The Ansible Automation Framework)
In Part 4, we successfully implemented an isolated, stateful memory system using an embedded SQLite3 database. Today, I decided to take a step back and try a few things before doing further refining of the model.
I want to see how we can move past raw terminal prompts and start organizing a programmatic workflow. I asked buddy how I can build an Ansible automation project for our network topology.
This is my question/answer session with buddy, with my comments after each question and answer.
My Question 1: Tell me about Ansible Components
ME:
Ask: I am thinking to start automating my network topology, I will be using Ansible for that. Can you tell me components of ansible that I need to know?
Assistant:
To effectively automate your Juniper topology (J1 through J6) using Ansible, you need to master several core components. Since you are working with **Juniper Junos 14.1R1.10**, focusing on the specific modules and ways Ansible interacts with Junos is key.
Here are the essential components of Ansible you need to know:
### 1. Inventory
The inventory is where you define your infrastructure. For your topology, this is where you will list your devices (J1-J6), their management IPs (e.g., `10.10.99.1`), and group them (e.g., `[core_switches]` or `[edge_routers]`).
* **Why it matters:** It allows Ansible to know *where* to push the configurations.
### 2. Modules (and Collections)
Modules are the "tools" in the toolbox. For Juniper, you should specifically focus on the **`juniper_networks` collection**.
* **Key Modules:** You will primarily use `junos_config` (to push configuration changes), `junos_command` (to run operational commands like `show` commands), and `junos_facts` (to gather system information).
* **Why it matters:** Instead of writing complex scripts, you call these modules to perform specific tasks on your Junos devices.
### 3. Playbooks
Playbooks are the "scripts" written in YAML. They map out the workflow of what you want to achieve (e.g., "Update the OSPF configuration on all routers").
* **Why it matters:** This is where you define the sequence of tasks for your automation.
### 4. Variables and Facts
* **Variables:** These are placeholders for data that might change, such as IP addresses or VLAN IDs. You can store these in `group_vars` or `host_vars`.
* **Facts:** These are pieces of information gathered by Ansible about the device (e.g., serial numbers, model types, or interface statuses).
* **Why it matters:** Using variables allows you to create "templates" so you don't have to hardcode every IP address for J1 through J6 individually.
### 5. Roles
Roles are a way to organize your automation into reusable components. Instead of one giant playbook, you can create roles like `bgp_config`, `interface_setup`, or `ntp_config`.
* **Why it matters:** As your AIOps platform grows, Roles allow you to reuse the same logic across different parts of your network.
### 6. Handlers
Handlers are special tasks that only run when "notified" by another task (e.g., a configuration change).
* **Why it matters:** In Junos, handlers are often used to trigger a `commit` or a `clear` command after a specific configuration change is applied.
### 7. Connection Plugins
Ansible needs a way to "talk" to the device. For Juniper, this usually happens via **NETCONF** or **SSH**.
* **Why it matters:** You need to configure your `ansible.cfg` to use the correct transport method to communicate with the Junos OS.
### Summary Roadmap for your Project:
1. **Inventory:** Define J1-J6 and their management IPs.
2. **Variables:** Map out the IP addresses from your topology (e.g., `172.16.14.1` for J1 em2).
3. **Playbooks/Modules:** Use `junos_config` to push the set-style configurations you've defined in your requirements.
4. **Roles:** Organize these into reusable blocks as you build out your AIOps platform.
Catching the Legacy Module Trap
While the structural breakdown was excellent, a critical review of the assistant's output revealed a very common local AI error. The model suggested using the generic juniper_networks collection.
In a modern automated architecture, that legacy setup is outdated. The correct collection namespace to target for modern playbooks is junipernetworks.junos, and the exact configuration rendering module is junipernetworks.junos.junos_config.
Catching this subtle drift is exactly why human-in-the-loop engineering validation is non-negotiable for AIOps right now. Other than that minor flag, it was an incredibly clean overview of how Ansible works.
Question 2: Provide me a directory structure for my ansible automation project, don't include roles.
ME:
Provide me a directory structure for my ansible automation project, don't include roles.
Assistant:
Based on best practices for enterprise network automation and the specific requirements of your project, here is a recommended directory structure for your Ansible automation project (excluding roles):
.
├── ansible.cfg # Main configuration file for Ansible
├── inventory/ # Inventory files defining your devices
│ ├── hosts.ini # Or hosts.yml (defining J1-J6)
│ └── production.yaml # Environment-specific inventories
├── group_vars/ # Variables shared by groups of devices
│ ├── all.yml # Global variables (e.g., DNS, NTP servers)
│ ├── juniper_devices.yml # Variables for the Juniper platform
│ └── mgmt_network.yml # Variables for the 10.10.99.0/24 network
├── host_vars/ # Host-specific variables (J1, J2, etc.)
│ ├── J1.yml # Specifics for J1 (e.g., em5 IP, lo0 IP)
│ ├── J2.yml
│ ├── J3.yml
│ ├── J4.yml
│ ├── J5.yml
│ └── J6.yml
├── playbooks/ # The main entry points for your automation
│ ├── site.yml # Master playbook
│ ├── provisioning.yml # Initial configuration playbooks
│ ├── config_backup.yml # Scheduled backup tasks
│ └── compliance_check.yml # Audit and validation scripts
├── scripts/ # Helper scripts (Python, Bash) for pre/post processing
├── tests/ # Test suites or local testing scripts
├── requirements.yml # List of external collections and dependencies
└── .gitignore # Standard git ignore file
### Key Components Explained:
* **`inventory/`**: Separates the physical topology from the logic.
* **`group_vars/` & `host_vars/`**: This is where you will store the specific IP addresses and interface details (like `em2`, `lo0`) defined in your blueprint, ensuring that playbooks remain generic and reusable.
* **`playbooks/`**: Contains the high-level logic for your AIOps platform's operations.
* **`ansible.cfg`**: Ensures that all team members use the same settings (e.g., `host_key_checking = False`, `inventory = ./inventory`).
My Thoughts
I deliberately asked the model to skip roles here because I want to use ansible-galaxy to cleanly initialize those directory structures later when the project scales up. Keeping it role-free for this experiment gives us a clean, flat, ultra-readable playground layout.
Question 3: Provide me script to build a directory structure for my ansible automation project, don't include roles.
ME:
Provide me script to build a directory structure for my ansible automation project, don't include roles.
Assistant:
To build a professional, scalable Ansible project structure for your AIOps platform without including roles, you can use the following shell script. This structure follows standard Ansible best practices by separating inventory, variables, and playbooks into distinct directories.
#!/bin/bash
# Project Name: AIOps_Network_Automation
# Purpose: Create a standardized directory structure for Juniper automation.
PROJECT_NAME="aiops_network_automation"
mkdir -p $PROJECT_NAME
cd $PROJECT_NAME
# Create core directories
mkdir -p inventory
mkdir -p group_vars
mkdir -p host_vars
mkdir -p playbooks
mkdir -p scripts
mkdir -p tests
mkdir -p filter_plugins
# Create initial files to get started
touch inventory/hosts.ini
touch requirements.txt
touch .ansible_tags
touch ansible.cfg
# Optional: Create a placeholder for your main playbook
touch playbooks/site.yml
echo "Directory structure for $PROJECT_NAME created successfully."
echo "Structure:"
ls -R
### Explanation of the Structure:
* **`inventory/`**: Contains your inventory files (e.g., `hosts.ini` or `hosts.yml`). This is where you will define J1 through J6.
* **`group_vars/`**: Used to store variables common to a group of devices (e.g., all Juniper devices sharing the same Junos version).
* **`host_vars/`**: Used for variables specific to individual devices (e.g., unique management IPs or local descriptions for J1, J2, etc.).
* **`playbooks/`**: Contains your high-level playbook instructions.
Running the Creation Script
I took Buddy's bash code, saved it directly into an automation script named ansible_starter.sh within my working folder layout, and ran it natively via my shell:
sh ansible_starter.sh
To verify the initialization, I fired up the native Linux tree utility tool on my hypervisor terminal. The filesystem cleanly snapped into position with 100% accuracy:
~/projects/ai_ops
╰─$ tree
.
├── aiops_network_automation
│ ├── ansible.cfg
│ ├── filter_plugins
│ ├── group_vars
│ ├── host_vars
│ ├── inventory
│ │ └── hosts.ini
│ ├── playbooks
│ │ └── site.yml
│ ├── requirements.txt
│ ├── scripts
│ └── tests
└── ansible_starter.sh
8 directories, 5 files
Architectural Conclusion & Next Steps
This execution run left me deeply impressed with devops-buddy's current trajectory. It correctly hardcoded our layout limits and organized our inventory nodes neatly.
But seeing the model suggest tools like junos_facts sparked a massive realization for where this homelab project needs to evolve. Right now, our assistant only knows what our network should look like because the design rules are baked into its weights. It is completely blind to what the network actually looks like right now.
To solve this, we need a Live Facts Layer. We can configure background automation scripts to pull live operational telemetry straight from our routers (such as OSPF neighbor adjacencies or interface link statuses) and commit that data to our SQL storage module.
By combining our structural conversation loops with live operational database facts, our assistant will transform from a configuration generator into a real-world network troubleshooting engine.
In Part 6, we will return to our coding modules to tackle text processing limits. We will focus on improving devops-buddy's semantic cache memory so that if it answers a technical question once, it remembers the entry perfectly—instantly matching different conversational variations of the exact same query without forcing our CPU cores to execute slow, repetitive brainstorming cycles from scratch.