🚀 Ansible Network Automation Beginner’s Village (4) – The Secret Weapon of the Variable Wizard
Network Engineer Comeback Plan Series – Part 4
Introduction: Congratulations on arriving at the Variable Wizard Academy in the Beginner’s Village! Now, you will upgrade from “Code Executor” to “Variable Wizard”, transforming from “Fixed Configuration” to “Intelligent Decision Making”. Are you ready? Today you will master the most powerful variable management techniques in Ansible!
🎯 Chapter Pain Points: Have you encountered these variable management nightmares?
😫 Common Crashes in Variable Management
Scenario 1: The Pain of Hardcoding
"Why do I have to manually change the IP address in every Playbook?"
"The configurations for the test environment and production environment are exactly the same, just different parameters, what should I do?"
"I changed one place and forgot to change others, now the configurations are inconsistent!"
Scenario 2: The Chaos of Variable Priority
"Why is my variable not taking effect?"
"Which variable's value will be used?"
"Why was the variable passed from the command line overridden?"
Scenario 3: The Dilemma of Obtaining Device Information
"I want to execute different tasks based on the device model, how do I obtain device information?"
"How to dynamically get the number and type of device interfaces?"
"Why can't I get the specific configuration information of the device?"
Scenario 4: The Trouble of Data Processing
"The data returned by the API is too complex, how do I extract the information I need?"
"The IP address format is inconsistent, how to standardize it?"
"How to convert device information into the format I need?"
If you are experiencing these challenges, congratulations, this chapter is your savior!
🎭 Variable Magic: Detailed Explanation of Ansible Variable Management
📝 Basic Concepts of Variables
Ansible Variables are containers for storing values that can be reused throughout the project. Imagine:
•Variables are like your “configuration templates”•Can be dynamically adjusted based on different environments•Reduces repetitive configurations and improves maintainability•Makes your Playbooks smarter and more flexible
🏷️ Variable Naming Rules
Variable naming conventions:
•Must start with a letter•Can only contain letters, numbers, and underscores•Case-sensitive•Meaningful names are recommended
# ✅ Good variable naming
dns_servers: [8.8.8.8, 8.8.4.4]
device_hostname: router01
vlan_id: 100
# ❌ Bad variable naming
a: 192.168.1.1
x1: "server"
VAR-NAME: "test"
🏆 Variable Priority: Who Calls the Shots?
The variable priority in Ansible is like a “power hierarchy”, the higher the position, the greater the priority:
1Group Variables (group_vars)2Host Variables (host_vars)3Collected Facts4Play Variables (vars, vars_files)5Task Variables6Command Line Variables (–extra-vars) 👑 Highest Priority
# Example: Practical Application of Variable Priority
- name: Variable Priority Demonstration
hosts: all
vars:
dns_server: "192.168.1.100" # 4th priority
tasks:
- name: Show DNS server
ansible.builtin.debug:
msg: "DNS server is: {{ dns_server }}"
# If the command line passes -e "dns_server=8.8.8.8", it will show 8.8.8.8
🔧 Using Variables in Playbooks
- name: Configure Device Hostname
hosts: cisco_devices
gather_facts: false
vars:
# Define variables
domain_name: "example.com"
site_code: "BJ"
tasks:
- name: Set Hostname
cisco.ios.ios_hostname:
config:
hostname: "{{ site_code }}-{{ inventory_hostname }}.{{ domain_name }}"
state: merged
⚠️ Important Reminder: When the variable value starts with
<span><span>{{ }}</span></span>, it must be enclosed in quotes, otherwise YAML will parse incorrectly!
💾 Registering Variables: Capturing Task Output
Using <span><span>register</span></span> keyword can save the output of a task into a variable:
- name: Get VLAN Information
cisco.ios.ios_vlans:
state: gathered
register: vlan_data
- name: Show VLAN Count
ansible.builtin.debug:
msg: "There are {{ vlan_data.vlans | length }} VLANs on the device"
- name: Show All VLAN Details
ansible.builtin.debug:
var: vlan_data.vlans
🎯 Special Variables: Ansible’s Built-in Magic
Ansible provides some special variables to control connections and behaviors:
# Connection-related special variables
ansible_connection: ansible.netcommon.network_cli
ansible_network_os: cisco.ios.ios
ansible_host: 192.168.1.1
ansible_user: admin
ansible_password: "your_password"
ansible_become: true
ansible_become_method: enable
# Magic Variables
inventory_hostname: "The name of the current host in the inventory"
group_names: "All groups the current host belongs to"
hostvars: "Dictionary of variables for all hosts"
groups: "Information about all groups in the inventory"
📁 Best Practices: Separating Variable Files
Separating variables from Playbooks improves maintainability:
project/
├── inventory
├── group_vars/
│ ├── cisco.yml # Cisco device group variables
│ ├── juniper.yml # Juniper device group variables
│ └── all.yml # Common variables for all devices
├── host_vars/
│ ├── router01.yml # Individual host variables
│ └── switch01.yml # Individual host variables
└── playbooks/
└── config.yml
Example: group_vars/cisco.yml
# Common configuration for Cisco devices
ntp_servers:
- 192.168.1.10
- 192.168.1.11
snmp_config:
location: "Beijing Data Center"
contact: "[email protected]"
community: "public"
🔍 Facts Magic: Obtaining Device Information
📊 What are Ansible Facts?
Ansible Facts are information that Ansible automatically collects from managed nodes, including:
•Device model and version•Interface configurations•Memory and CPU usage•Network configurations•System information
🛠️ Methods of Collecting Facts
1. Default Collection
- name: Collect Device Information
hosts: all
gather_facts: true # Default is true, collects basic facts
tasks:
- name: Show Device Model
ansible.builtin.debug:
msg: "Device Model: {{ ansible_facts['net_model'] }}"
2. Specifying Collection Scope
- name: Collect Specific Information
hosts: all
gather_facts: false
tasks:
- name: Collect Interface Information
cisco.ios.ios_facts:
gather_subset:
- interfaces
- hardware
gather_network_resources:
- interfaces
- vlans
3. Collecting All Information
- name: Collect All Information
hosts: all
gather_facts: false
tasks:
- name: Collect Complete Device Information
cisco.ios.ios_facts:
gather_subset: all
🎭 Practical Application of Facts
Configuring NTP Based on Device Type
- name: Configure NTP Based on Device Type
hosts: all
gather_facts: true
tasks:
- name: Configure NTP for Cisco Devices
cisco.ios.ios_ntp:
servers: "{{ ntp_servers }}"
when: ansible_network_os 'cisco.ios.ios'
- name: Configure NTP for Juniper Devices
junipernetworks.junos.junos_ntp:
servers: "{{ ntp_servers }}"
when: ansible_network_os 'junipernetworks.junos.junos'
Dynamic Configuration Based on Interface Count
- name: Configure VLAN Based on Interface Count
hosts: all
gather_facts: true
tasks:
- name: Show Interface Count
ansible.builtin.debug:
msg: "The device has {{ ansible_facts['net_interfaces'] | length }} interfaces"
- name: Large Switch Configuration
ansible.builtin.debug:
msg: "This is a large switch, more VLANs need to be configured"
when: ansible_facts['net_interfaces'] | length > 24
🔮 The Clever Use of Magic Variables
Obtaining Information from Other Hosts
- name: Get Information from Other Hosts
hosts: all
gather_facts: true
tasks:
- name: Show Hostname of the First Cisco Device
ansible.builtin.debug:
msg: "First Cisco Device: {{ hostvars[groups['cisco'][0]]['ansible_facts']['net_hostname'] }}"
Executing Tasks Based on Group Membership
- name: Configure Based on Group Information
hosts: all
gather_facts: true
tasks:
- name: Data Center Device Configuration
ansible.builtin.debug:
msg: "This is a data center device"
when: "'dc_devices' in group_names"
📋 Survey Magic: Dynamic Variables of the Automation Controller
🎯 What are Surveys?
Surveys are interactive forms in the Automation Controller that allow dynamic input of variable values during Playbook execution.
🔧 Features of Surveys
•User-Friendly: Provides a GUI interface for parameter input•Validation Functionality: Supports validation for various data types•Dynamic Configuration: Different parameters can be input for each run•Highest Priority: Variables set in surveys have the highest priority
📝 Types of Survey Questions
•Text: Single-line text input•Textarea: Multi-line text input•Password: Password input (encrypted display)•Single Choice: Choose one from options•Multiple Choice: Choose multiple from options•Integer: Numeric input•Float: Decimal input
💼 Practical Application of Surveys
Example: Creating a Survey for Device Configuration
# Configure Playbook - config_device.yml
- name: Dynamically Configure Device
hosts: "{{ target_devices }}"
gather_facts: false
vars:
# These variables will be provided through the survey
device_hostname: "{{ survey_hostname }}"
dns_servers: "{{ survey_dns_servers }}"
ntp_enabled: "{{ survey_ntp_enabled }}"
tasks:
- name: Configure Hostname
cisco.ios.ios_hostname:
config:
hostname: "{{ device_hostname }}"
- name: Configure DNS
cisco.ios.ios_system:
name_servers: "{{ dns_servers }}"
- name: Configure NTP
cisco.ios.ios_ntp:
servers: "{{ ntp_servers }}"
when: ntp_enabled == true
Corresponding Survey Configuration:
1
target_devices: Multiple Choice (Multi-select)
•Options: cisco_devices, juniper_devices, all_devices2
survey_hostname: Text
•Prompt: Please enter the device hostname3
survey_dns_servers: Textarea
•Prompt: Please enter the DNS server list (one per line)4
survey_ntp_enabled: Multiple Choice (Single-select)
•Options: true, false
🎨 Filter Magic: The Swiss Army Knife of Data Processing
🔧 What are Filters?
Filters are functionalities provided by Jinja2 for processing and transforming data. Format:<span><span>{{ variable | filter }}</span></span>
🌐 Network Information Filters
<span><span>ansible.utils.ipaddr</span></span> filters are powerful tools for network automation:
- name: Network Address Processing Example
hosts: localhost
gather_facts: false
vars:
ip_address: "192.168.1.1/24"
network_list:
- "192.168.1.0/24"
- "10.0.0.0/8"
- "172.16.0.0/12"
tasks:
- name: Validate IP Address
ansible.builtin.debug:
msg: "{{ ip_address | ansible.utils.ipaddr }}"
- name: Get Network Address
ansible.builtin.debug:
msg: "Network Address: {{ ip_address | ansible.utils.ipaddr('network') }}"
- name: Get Broadcast Address
ansible.builtin.debug:
msg: "Broadcast Address: {{ ip_address | ansible.utils.ipaddr('broadcast') }}"
- name: Get Subnet Mask
ansible.builtin.debug:
msg: "Subnet Mask: {{ ip_address | ansible.utils.ipaddr('netmask') }}"
- name: Get Available IP Count
ansible.builtin.debug:
msg: "Available IP Count: {{ ip_address | ansible.utils.ipaddr('numhosts') }}"
🎭 Commonly Used Filters
Data Formatting
- name: Data Formatting Example
hosts: localhost
gather_facts: false
vars:
device_list:
- name: router01
ip: 192.168.1.1
model: Cisco ISR4331
- name: switch01
ip: 192.168.1.2
model: Cisco C9300
tasks:
- name: Convert to YAML Format
ansible.builtin.debug:
msg: "{{ device_list | to_nice_yaml }}"
- name: Convert to JSON Format
ansible.builtin.debug:
msg: "{{ device_list | to_nice_json }}"
- name: Get Device Name List
ansible.builtin.debug:
msg: "Device List: {{ device_list | map(attribute='name') | list }}"
Data Filtering
- name: Data Filtering Example
hosts: localhost
gather_facts: false
vars:
interfaces:
- name: GigabitEthernet0/0
ip: 192.168.1.1
status: up
- name: GigabitEthernet0/1
ip: 192.168.1.2
status: down
- name: GigabitEthernet0/2
ip: 192.168.1.3
status: up
tasks:
- name: Get All Enabled Interfaces
ansible.builtin.debug:
msg: "{{ interfaces | selectattr('status', 'equalto', 'up') | list }}"
- name: Get Interface Name List
ansible.builtin.debug:
msg: "{{ interfaces | map(attribute='name') | list }}"
String Processing
- name: String Processing Example ##FYC Note: If you encounter issues here, feel free to message me
hosts: localhost
gather_facts: false
vars:
hostname: "router01.example.com"
config_text: |
interface GigabitEthernet0/0
ip address 192.168.1.1 255.255.255.0
no shutdown
exit
tasks:
- name: Convert String to Uppercase
ansible.builtin.debug:
msg: "{{ hostname | upper }}"
- name: Extract Domain Name
ansible.builtin.debug:
msg: "{{ hostname | regex_replace('^.*\.', '') }}"
- name: Extract IP Address from Configuration
ansible.builtin.debug:
msg: "{{ config_text | regex_findall('\d+\.\d+\.\d+\.\d+') }}"
🏆 Practical Cases: 3 Enterprise-Level Playbooks
📋 Case 1: Smart Device Configuration Manager
Application Scenario: Automatically configure network devices based on device type and location
File Structure:
project/
├── inventory
├── group_vars/
│ ├── cisco.yml
│ ├── juniper.yml
│ └── all.yml
├── host_vars/
│ ├── bj-router01.yml
│ └── sh-switch01.yml
└── playbooks/
└── smart_device_config.yml
Variable File (group_vars/all.yml):
# Global Configuration Variables
global_settings:
ntp_servers:
- 192.168.1.10
- 192.168.1.11
dns_servers:
- 8.8.8.8
- 8.8.4.4
snmp_community: "public"
snmp_contact: "[email protected]"
# Site Configuration
site_config:
beijing:
location: "Beijing Data Center A"
timezone: "CST"
syslog_servers:
- 192.168.100.10
- 192.168.100.11
shanghai:
location: "Shanghai Data Center B"
timezone: "CST"
syslog_servers:
- 192.168.200.10
- 192.168.200.11
Variable File (group_vars/cisco.yml):
# Cisco Device Specific Configuration
cisco_config:
banner_login: |
**************************************
* Cisco Device Managed by Ansible *
* Unauthorized Access Prohibited *
**************************************
service_password_encryption: true
logging:
facility: local7
trap_level: informational
Main Playbook (smart_device_config.yml):
---
- name: Smart Device Configuration Manager
hosts: all
gather_facts: true
# Dynamically include variable files
vars_files:
- group_vars/all.yml
- group_vars/{{ ansible_network_os | regex_replace('\.', '_') }}.yml
tasks:
# Step 1: Collect and Analyze Device Information
- name: Collect Detailed Device Information
setup:
gather_subset:
- network
- hardware
- name: Show Device Information
ansible.builtin.debug:
msg: |
Device: {{ inventory_hostname }}
Type: {{ ansible_network_os }}
Model: {{ ansible_facts.net_model }}
Site: {{ site_code }}
# Step 2: Configure Based on Device Type and Site
- name: Configure Cisco Devices
block:
- name: Set Hostname
cisco.ios.ios_hostname:
config:
hostname: "{{ site_code }}-{{ inventory_hostname | regex_replace('\..*$', '') }}"
- name: Configure Login Banner
cisco.ios.ios_banner:
banner: login
text: "{{ cisco_config.banner_login }}"
state: present
- name: Configure NTP
cisco.ios.ios_ntp:
servers: "{{ global_settings.ntp_servers }}"
logging: true
- name: Configure DNS
cisco.ios.ios_system:
name_servers: "{{ global_settings.dns_servers }}"
domain_lookup: true
- name: Configure SNMP
cisco.ios.ios_snmp_server:
state: merged
config:
location: "{{ site_config[site_code].location }}"
contact: "{{ global_settings.snmp_contact }}"
communities:
- name: "{{ global_settings.snmp_community }}"
access: ro
- name: Configure Syslog
cisco.ios.ios_logging_global:
config:
facility: "{{ cisco_config.logging.facility }}"
trap: "{{ cisco_config.logging.trap_level }}"
hosts: "{{ site_config[site_code].syslog_servers | map('ansible.utils.ipaddr', 'address') | list }}"
- name: Enable Password Encryption
cisco.ios.ios_config:
lines:
- service password-encryption
when: ansible_network_os 'cisco.ios.ios'
- name: Configure Juniper Devices
block:
- name: Configure Juniper Devices
junipernetworks.junos.junos_system:
hostname: "{{ site_code }}-{{ inventory_hostname | regex_replace('\..*$', '') }}"
domain_search: ["{{ domain_name }}"]
name_servers: "{{ global_settings.dns_servers }}"
- name: Configure NTP
junipernetworks.junos.junos_ntp:
servers: "{{ global_settings.ntp_servers }}"
when: ansible_network_os 'junipernetworks.junos.junos'
# Step 3: Configuration Verification
- name: Verify Configuration
block:
- name: Check NTP Configuration
cisco.ios.ios_command:
commands:
- show ntp status
register: ntp_status
when: ansible_network_os 'cisco.ios.ios'
- name: Show NTP Status
ansible.builtin.debug:
msg: "{{ ntp_status.stdout_lines[0] }}"
when: ansible_network_os 'cisco.ios.ios'
- name: Check DNS Resolution
ansible.builtin.command:
cmd: "nslookup {{ global_settings.dns_servers[0] }}"
register: dns_check
failed_when: dns_check.rc != 0
delegate_to: localhost
- name: DNS Resolution Successful
ansible.builtin.debug:
msg: "DNS configuration verification successful"
rescue:
- name: Configuration Verification Failed
ansible.builtin.debug:
msg: "There was an issue with configuration verification, please check the logs"
# Step 4: Generate Configuration Report
- name: Generate Configuration Report
ansible.builtin.copy:
content: |
Device Configuration Report
==================
Device Name: {{ inventory_hostname }}
Configuration Time: {{ ansible_date_time.iso8601 }}
Device Type: {{ ansible_network_os }}
Device Model: {{ ansible_facts.net_model }}
Software Version: {{ ansible_facts.net_version }}
Site Code: {{ site_code }}
Configuration Status: Completed
NTP Servers: {{ global_settings.ntp_servers | join(', ') }}
DNS Servers: {{ global_settings.dns_servers | join(', ') }}
Syslog Servers: {{ site_config[site_code].syslog_servers | join(', ') }}
dest: "/tmp/config_report_{{ inventory_hostname }}.txt"
mode: 0644
delegate_to: localhost
- name: Summarize All Device Reports
ansible.builtin.debug:
msg: "Device {{ inventory_hostname }} configuration completed, report generated"
run_once: true
📊 Case 2: Network Device Information Collection and Analysis System
Application Scenario: Collect network device information and generate detailed network status reports
Main Playbook (network_inventory_collector.yml):
---
- name: Network Device Information Collection and Analysis System
hosts: all
gather_facts: true
vars:
# Output Directory
output_dir: "/tmp/network_inventory"
# Types of Information to Collect
gather_info:
- basic_info
- interfaces
- vlans
- protocols
- hardware
# Report Template
report_template: |
Detailed Network Device Report
=====================================
Device Name: {{ inventory_hostname }}
Report Generation Time: {{ ansible_date_time.iso8601 }}
Basic Information
-------------------------
Device Type: {{ ansible_network_os }}
Device Model: {{ ansible_facts.net_model }}
Software Version: {{ ansible_facts.net_version }}
Serial Number: {{ ansible_facts.net_serialnum }}
Uptime: {{ ansible_facts.net_uptime }}
Interface Information
-------------------------
{% for interface in ansible_facts.net_interfaces.values() %}
Interface Name: {{ interface.description }}
MAC Address: {{ interface.macaddress }}
MTU: {{ interface.mtu }}
Status: {{ interface.operstatus }}
{% endfor %}
VLAN Information
-------------------------
{% if ansible_network_resources.vlans is defined %}
{% for vlan in ansible_network_resources.vlans %}
VLAN ID: {{ vlan.vlan_id }}
VLAN Name: {{ vlan.name }}
{% endfor %}
{% else %}
No VLAN information obtained
{% endif %}
tasks:
# Step 1: Preparation
- name: Create Output Directory
ansible.builtin.file:
path: "{{ output_dir }}"
state: directory
mode: 0755
run_once: true
delegate_to: localhost
# Step 2: Collect Device Information
- name: Collect Basic Information
setup:
gather_subset: "{{ gather_info }}"
- name: Collect Network Resource Information
block:
- name: Collect Cisco Device Resource Information
cisco.ios.ios_facts:
gather_network_resources:
- interfaces
- vlans
- l3_interfaces
when: ansible_network_os 'cisco.ios.ios'
- name: Collect Juniper Device Resource Information
junipernetworks.junos.junos_facts:
gather_network_resources:
- interfaces
- vlans
- l3_interfaces
when: ansible_network_os 'junipernetworks.junos.junos'
# Step 3: Data Analysis and Processing
- name: Analyze Interface Status
ansible.builtin.set_fact:
interface_stats: "{{ ansible_facts.net_interfaces.values() | list }}"
up_interfaces: "{{ ansible_facts.net_interfaces.values() | selectattr('operstatus', 'equalto', 'up') | list }}"
down_interfaces: "{{ ansible_facts.net_interfaces.values() | selectattr('operstatus', 'equalto', 'down') | list }}"
- name: Show Interface Statistics
ansible.builtin.debug:
msg: |
Device {{ inventory_hostname }} Interface Statistics:
Total Interfaces: {{ interface_stats | length }}
Enabled Interfaces: {{ up_interfaces | length }}
Disabled Interfaces: {{ down_interfaces | length }}
- name: Check Interface Issues
ansible.builtin.debug:
msg: "Note: Device {{ inventory_hostname }} has {{ down_interfaces | length }} interfaces in a down state"
when: down_interfaces | length > 0
# Step 4: Generate Detailed Report
- name: Generate Detailed Device Report
ansible.builtin.copy:
content: "{{ report_template }}"
dest: "{{ output_dir }}/{{ inventory_hostname }}_detailed_report.txt"
mode: 0644
delegate_to: localhost
- name: Generate YAML Format Report
ansible.builtin.copy:
content: "{{ ansible_facts | to_nice_yaml }}"
dest: "{{ output_dir }}/{{ inventory_hostname }}_facts.yml"
mode: 0644
delegate_to: localhost
- name: Generate JSON Format Report
ansible.builtin.copy:
content: "{{ ansible_facts | to_nice_json }}"
dest: "{{ output_dir }}/{{ inventory_hostname }}_facts.json"
mode: 0644
delegate_to: localhost
# Step 5: Generate Summary Report
- name: Summarize All Device Information
ansible.builtin.copy:
content: |
Network Device Summary Report
====================================
Report Generation Time: {{ ansible_date_time.iso8601 }}
Total Devices: {{ groups.all | length }}
Cisco Device Count: {{ groups.cisco | length | default(0) }}
Juniper Device Count: {{ groups.juniper | length | default(0) }}
Device List:
{% for host in groups.all %}
- {{ host }}
{% endfor %}
Interface Statistics Summary:
{% for host in groups.all %}
- {{ host }}: {{ hostvars[host].interface_stats | length | default(0) }} interfaces
{% endfor %}
dest: "{{ output_dir }}/network_summary_report.txt"
mode: 0644
run_once: true
delegate_to: localhost
# Step 6: Data Export and Processing
- name: Export Device Interface Information to CSV
ansible.builtin.copy:
content: |
Device,Interface,Status,MAC_Address,MTU,Description
{% for interface in ansible_facts.net_interfaces.values() %}
{{ inventory_hostname }},{{ interface.description }},{{ interface.operstatus }},{{ interface.macaddress }},{{ interface.mtu }},{{ interface.description }}
{% endfor %}
dest: "{{ output_dir }}/interfaces_{{ inventory_hostname }}.csv"
mode: 0644
delegate_to: localhost
- name: Merge All Interface Information
ansible.builtin.shell:
cmd: |
echo "Device,Interface,Status,MAC_Address,MTU,Description" > {{ output_dir }}/all_interfaces.csv
cat {{ output_dir }}/interfaces_*.csv | grep -v "Device," >> {{ output_dir }}/all_interfaces.csv
run_once: true
delegate_to: localhost
# Step 7: Generate Issue List
- name: Generate Issue List
ansible.builtin.copy:
content: |
Network Device Issue List
======================================
Generation Time: {{ ansible_date_time.iso8601 }}
{% for host in groups.all %}
{% if hostvars[host].down_interfaces is defined and hostvars[host].down_interfaces | length > 0 %}
Device {{ host }} Issues:
{% for interface in hostvars[host].down_interfaces %}
- Interface {{ interface.description }} is in a down state
{% endfor %}
{% endif %}
{% endfor %}
dest: "{{ output_dir }}/issues_report.txt"
mode: 0644
run_once: true
delegate_to: localhost
# Step 8: Completion Notification
- name: Collection Completion Notification
ansible.builtin.debug:
msg: |
Network device information collection completed!
Output Directory: {{ output_dir }}
Generated Files:
- Detailed report for each device
- Summary report
- Interface information CSV file
- Issue list
run_once: true
🎛️ Case 3: Automation Controller Survey-Driven Configuration System
Application Scenario: Achieve dynamic, interactive network device configuration through the survey feature of the Automation Controller
Main Playbook (survey_driven_config.yml):
---
- name: Survey-Driven Network Device Configuration System
hosts: "{{ target_device_group | default('all') }}"
gather_facts: true
vars:
# These variables will be provided through the survey
config_type: "{{ survey_config_type | default('basic') }}"
hostname_prefix: "{{ survey_hostname_prefix | default('NET') }}"
domain_name: "{{ survey_domain_name | default('example.com') }}"
dns_enabled: "{{ survey_dns_enabled | default(true) }}"
ntp_enabled: "{{ survey_ntp_enabled | default(true) }}"
snmp_enabled: "{{ survey_snmp_enabled | default(true) }}"
syslog_enabled: "{{ survey_syslog_enabled | default(true) }}"
# Network Service Configuration
network_services:
dns_servers: "{{ survey_dns_servers | default(['8.8.8.8', '8.8.4.4']) }}"
ntp_servers: "{{ survey_ntp_servers | default(['192.168.1.10', '192.168.1.11']) }}"
syslog_servers: "{{ survey_syslog_servers | default(['192.168.100.10']) }}"
# SNMP Configuration
snmp_config:
location: "{{ survey_snmp_location | default('Data Center') }}"
contact: "{{ survey_snmp_contact | default('[email protected]') }}"
community_ro: "{{ survey_snmp_ro_community | default('public') }}"
community_rw: "{{ survey_snmp_rw_community | default('private') }}"
tasks:
# Step 1: Configuration Verification and Preparation
- name: Verify Survey Parameters
ansible.builtin.debug:
msg: |
Configuration Type: {{ config_type }}
Hostname Prefix: {{ hostname_prefix }}
Domain Name: {{ domain_name }}
DNS Enabled: {{ dns_enabled }}
NTP Enabled: {{ ntp_enabled }}
SNMP Enabled: {{ snmp_enabled }}
Syslog Enabled: {{ syslog_enabled }}
- name: Verify Network Service Addresses
ansible.builtin.debug:
msg: "{{ item | ansible.utils.ipaddr }}"
loop: "{{ network_services.dns_servers + network_services.ntp_servers + network_services.syslog_servers }}"
when: item | ansible.utils.ipaddr is not none
# Step 2: Basic Configuration
- name: Basic Device Configuration
block:
- name: Set Device Hostname
cisco.ios.ios_hostname:
config:
hostname: "{{ hostname_prefix }}-{{ inventory_hostname | regex_replace('\..*$', '') }}.{{ domain_name }}"
when: ansible_network_os 'cisco.ios.ios'
- name: Set Juniper Hostname
junipernetworks.junos.junos_system:
hostname: "{{ hostname_prefix }}-{{ inventory_hostname | regex_replace('\..*$', '') }}"
domain_search: ["{{ domain_name }}"]
when: ansible_network_os 'junipernetworks.junos.junos'
- name: Configure Login Banner
cisco.ios.ios_banner:
banner: login
text: |
**************************************
* Device Managed by Ansible *
* Configuration Type: {{ config_type }} *
* Configured on: {{ ansible_date_time.iso8601 }} *
**************************************
state: present
when: ansible_network_os 'cisco.ios.ios'
- name: Enable Password Encryption
cisco.ios.ios_config:
lines:
- service password-encryption
when: ansible_network_os 'cisco.ios.ios'
# Step 3: DNS Configuration
- name: Configure DNS Service
block:
- name: Configure Cisco DNS
cisco.ios.ios_system:
name_servers: "{{ network_services.dns_servers }}"
domain_lookup: "{{ dns_enabled }}"
when: ansible_network_os 'cisco.ios.ios'
- name: Configure Juniper DNS
junipernetworks.junos.junos_system:
name_servers: "{{ network_services.dns_servers }}"
when: ansible_network_os 'junipernetworks.junos.junos'
- name: Verify DNS Configuration
ansible.builtin.command:
cmd: "nslookup {{ network_services.dns_servers[0] }}"
register: dns_test
delegate_to: localhost
failed_when: dns_test.rc != 0
- name: DNS Configuration Successful
ansible.builtin.debug:
msg: "DNS configuration verification successful"
when: dns_enabled true
# Step 4: NTP Configuration
- name: Configure NTP Service
block:
- name: Configure Cisco NTP
cisco.ios.ios_ntp:
servers: "{{ network_services.ntp_servers }}"
logging: true
when: ansible_network_os 'cisco.ios.ios'
- name: Configure Juniper NTP
junipernetworks.junos.junos_ntp:
servers: "{{ network_services.ntp_servers }}"
when: ansible_network_os 'junipernetworks.junos.junos'
- name: Verify NTP Configuration
cisco.ios.ios_command:
commands:
- show ntp status
register: ntp_status
when: ansible_network_os 'cisco.ios.ios'
- name: Show NTP Status
ansible.builtin.debug:
msg: "{{ ntp_status.stdout_lines[0] }}"
when: ansible_network_os 'cisco.ios.ios'
when: ntp_enabled true
# Step 5: SNMP Configuration
- name: Configure SNMP Service
block:
- name: Configure Cisco SNMP
cisco.ios.ios_snmp_server:
state: merged
config:
location: "{{ snmp_config.location }}"
contact: "{{ snmp_config.contact }}"
communities:
- name: "{{ snmp_config.community_ro }}"
access: ro
- name: "{{ snmp_config.community_rw }}"
access: rw
traps:
snmp:
authentication: true
linkdown: true
linkup: true
when: ansible_network_os 'cisco.ios.ios'
- name: Configure Juniper SNMP
junipernetworks.junos.junos_snmp_server:
state: merged
config:
location: "{{ snmp_config.location }}"
contact: "{{ snmp_config.contact }}"
communities:
- name: "{{ snmp_config.community_ro }}"
authorization: read-only
- name: "{{ snmp_config.community_rw }}"
authorization: read-write
when: ansible_network_os 'junipernetworks.junos.junos'
- name: Verify SNMP Configuration
ansible.builtin.command:
cmd: "snmpwalk -v2c -c {{ snmp_config.community_ro }} {{ ansible_host }} sysDescr.0"
register: snmp_test
delegate_to: localhost
failed_when: snmp_test.rc != 0
ignore_errors: yes
- name: SNMP Configuration Completed
ansible.builtin.debug:
msg: "SNMP configuration completed"
when: snmp_enabled true
# Step 6: Syslog Configuration
- name: Configure Syslog Service
block:
- name: Configure Cisco Syslog
cisco.ios.ios_logging_global:
config:
facility: local7
trap: informational
hosts: "{{ network_services.syslog_servers | map('ansible.utils.ipaddr', 'address') | list }}"
when: ansible_network_os 'cisco.ios.ios'
- name: Configure Juniper Syslog
junipernetworks.junos.junos_system:
syslog:
hosts: "{{ network_services.syslog_servers }}"
when: ansible_network_os 'junipernetworks.junos.junos'
- name: Verify Syslog Configuration
cisco.ios.ios_command:
commands:
- show logging
register: logging_status
when: ansible_network_os 'cisco.ios.ios'
- name: Show Syslog Status
ansible.builtin.debug:
msg: "Syslog configuration completed"
when: syslog_enabled true
# Step 7: Configuration Verification and Reporting
- name: Generate Configuration Report
ansible.builtin.copy:
content: |
Device Configuration Report
================
Device Name: {{ inventory_hostname }}
Configuration Time: {{ ansible_date_time.iso8601 }}
Configuration Type: {{ config_type }}
Basic Configuration:
- Hostname: {{ hostname_prefix }}-{{ inventory_hostname | regex_replace('\..*$', '') }}.{{ domain_name }}
- Domain Name: {{ domain_name }}
Service Configuration:
- DNS: {{ 'Enabled' if dns_enabled else 'Disabled' }}
- NTP: {{ 'Enabled' if ntp_enabled else 'Disabled' }}
- SNMP: {{ 'Enabled' if snmp_enabled else 'Disabled' }}
- Syslog: {{ 'Enabled' if syslog_enabled else 'Disabled' }}
Configured Servers:
{% if dns_enabled %}
- DNS Servers: {{ network_services.dns_servers | join(', ') }}
{% endif %}
{% if ntp_enabled %}
- NTP Servers: {{ network_services.ntp_servers | join(', ') }}
{% endif %}
{% if syslog_enabled %}
- Syslog Servers: {{ network_services.syslog_servers | join(', ') }}
{% endif %}
SNMP Configuration:
{% if snmp_enabled %}
- Location: {{ snmp_config.location }}
- Contact: {{ snmp_config.contact }}
- Read-Only Community: {{ snmp_config.community_ro }}
- Read-Write Community: {{ snmp_config.community_rw }}
{% endif %}
dest: "/tmp/config_report_{{ inventory_hostname }}.txt"
mode: 0644
delegate_to: localhost
# Step 8: Configuration Completion Notification
- name: Configuration Completion Notification
ansible.builtin.debug:
msg: |
Device {{ inventory_hostname }} configuration completed!
Configuration Type: {{ config_type }}
Report File: /tmp/config_report_{{ inventory_hostname }}.txt
Corresponding Automation Controller Survey Configuration:
Survey Question Settings:
1
target_device_group (Multiple Choice – Single Select)
•Options: all, cisco, juniper•Default Value: all•Prompt: Select the device group to configure2
survey_config_type (Multiple Choice – Single Select)
•Options: basic, standard, advanced•Default Value: basic•Prompt: Select configuration type3
survey_hostname_prefix (Text)
•Default Value: NET•Prompt: Enter hostname prefix4
survey_domain_name (Text)
•Default Value: example.com•Prompt: Enter domain name5
survey_dns_enabled (Multiple Choice – Single Select)
•Options: true, false•Default Value: true•Prompt: Enable DNS or not6
survey_dns_servers (Textarea)
•Default Value: 8.8.8.8
8.8.4.4•Prompt: Enter DNS server list (one per line)7
survey_ntp_enabled (Multiple Choice – Single Select)
•Options: true, false•Default Value: true•Prompt: Enable NTP or not8
survey_ntp_servers (Textarea)
•Default Value: 192.168.1.10
192.168.1.11•Prompt: Enter NTP server list (one per line)9
survey_snmp_enabled (Multiple Choice – Single Select)
•Options: true, false•Default Value: true•Prompt: Enable SNMP or not10
survey_snmp_location (Text)
•Default Value: Data Center•Prompt: SNMP location information11
survey_snmp_contact (Text)
•Default Value: [email protected]•Prompt: SNMP contact person12
survey_snmp_ro_community (Text)
•Default Value: public•Prompt: SNMP read-only community name13
survey_snmp_rw_community (Password)
•Default Value: private•Prompt: SNMP read-write community name14
survey_syslog_enabled (Multiple Choice – Single Select)
•Options: true, false•Default Value: true•Prompt: Enable Syslog or not15
survey_syslog_servers (Textarea)
•Default Value: 192.168.100.10•Prompt: Enter Syslog server list (one per line)
🎓 Chapter Summary
🔑 Mastering Core Skills
Variable Management
•✅ Understand variable priority and scope•✅ Master variable naming conventions•✅ Learn to separate configuration using variable files•✅ Proficiently apply registered variables
Facts Collection
•✅ Automatically collect device information•✅ Use magic variables to obtain environmental information•✅ Make dynamic decisions based on device information•✅ Generate detailed device reports
Survey Functionality
•✅ Create interactive configuration interfaces•✅ Dynamic parameter input and validation•✅ Increase configuration flexibility•✅ Lower the usage threshold
Filter Applications
•✅ Network address processing and validation•✅ Data formatting and transformation•✅ String and text processing•✅ Complex data filtering and extraction
🚀 Practical Value
Enterprise-Level Applications
•Standardization of automated device configuration•Network information collection and monitoring•Dynamic configuration management•Detailed report generation
Operational Efficiency Improvement
•Reduce repetitive configuration work•Improve configuration accuracy•Quick fault diagnosis•Standardize operational processes
📈 Advanced Directions
Next Chapter PreviewCongratulations on completing the study of Ansible Variable Wizard! In the next chapter, we will enter more advanced topics:
•Advanced Playbook Structure Design•Using Roles and Collections•Error Handling and Debugging Techniques•Performance Optimization and Best Practices
Continue your journey of network engineering, truly transforming from a “configurer” to an “automation architect”!
🎯 Learning Path Review
📚 Completed Chapters
1Beginner’s Village (1) – The Comeback Journey of CLI Novices: ✅ Completed2Beginner’s Village (2) – Playbook Practical Wizard: ✅ Completed3Beginner’s Village (3) – Enterprise-Level Automation Architect: ✅ Completed4Beginner’s Village (4) – The Secret Weapon of the Variable Wizard: ✅ Completed
🚀 Next Stop
Chapter 5: Advanced Playbook Architect
•Advanced Applications of Roles and Collections•Error Handling and Debugging Advanced Techniques•Performance Optimization and Best Practices•Enterprise-Level Automation Architecture Design
Keep the passion for learning alive, your automation journey has just begun! 🎉