Ansible Network Automation Beginner’s Village (4) – The Secret Weapon of the Variable Wizard

🚀 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 environmentsReduces repetitive configurations and improves maintainabilityMakes your Playbooks smarter and more flexible

🏷️ Variable Naming Rules

Variable naming conventions:

Must start with a letterCan only contain letters, numbers, and underscoresCase-sensitiveMeaningful 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 versionInterface configurationsMemory and CPU usageNetwork configurationsSystem 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 &gt; 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 inputValidation Functionality: Supports validation for various data typesDynamic Configuration: Different parameters can be input for each runHighest Priority: Variables set in surveys have the highest priority

📝 Types of Survey Questions

Text: Single-line text inputTextarea: Multi-line text inputPassword: Password input (encrypted display)Single Choice: Choose one from optionsMultiple Choice: Choose multiple from optionsInteger: Numeric inputFloat: 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 &gt; 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" &gt; {{ output_dir }}/all_interfaces.csv
          cat {{ output_dir }}/interfaces_*.csv | grep -v "Device," &gt;&gt; {{ 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 &gt; 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, juniperDefault Value: allPrompt: Select the device group to configure2

survey_config_type (Multiple Choice – Single Select)

Options: basic, standard, advancedDefault Value: basicPrompt: Select configuration type3

survey_hostname_prefix (Text)

Default Value: NETPrompt: Enter hostname prefix4

survey_domain_name (Text)

Default Value: example.comPrompt: Enter domain name5

survey_dns_enabled (Multiple Choice – Single Select)

Options: true, falseDefault Value: truePrompt: 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, falseDefault Value: truePrompt: 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, falseDefault Value: truePrompt: Enable SNMP or not10

survey_snmp_location (Text)

Default Value: Data CenterPrompt: SNMP location information11

survey_snmp_contact (Text)

Default Value: [email protected]Prompt: SNMP contact person12

survey_snmp_ro_community (Text)

Default Value: publicPrompt: SNMP read-only community name13

survey_snmp_rw_community (Password)

Default Value: privatePrompt: SNMP read-write community name14

survey_syslog_enabled (Multiple Choice – Single Select)

Options: true, falseDefault Value: truePrompt: Enable Syslog or not15

survey_syslog_servers (Textarea)

Default Value: 192.168.100.10Prompt: 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 configurationNetwork information collection and monitoringDynamic configuration managementDetailed report generation

Operational Efficiency Improvement

Reduce repetitive configuration workImprove configuration accuracyQuick fault diagnosisStandardize 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 DesignUsing Roles and CollectionsError Handling and Debugging TechniquesPerformance 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 CollectionsError Handling and Debugging Advanced TechniquesPerformance Optimization and Best PracticesEnterprise-Level Automation Architecture Design

Keep the passion for learning alive, your automation journey has just begun! 🎉

Leave a Comment