Ansible Firefighting Hotline Series (9): Automating NetworkManager Management with Ansible Role

Ansible Firefighting Hotline Series (9): Automating NetworkManager Management with Ansible Role

#Linux #Automation #Ansible #Network

πŸ”₯ Say Goodbye to Complexity! Why is Network Configuration in Need of Automation?

Dear operations engineers, SREs, and cloud engineers, please recall these frustrating moments:

β€’New Machine Deployment 🀯: Dozens of new servers arrive, and you need to log in one by one, typing repetitive <span><span>nmcli</span></span> commands to configure static IPs, gateways, and DNS. The process is lengthy and prone to errors. A single incorrect IP could lead to the failure of the entire application deployment.β€’Bulk Changes β˜•οΈ->πŸ₯Ά: Suddenly notified, “All servers need to change their backup DNS!”. What was once a leisurely afternoon tea time instantly turns into a “copy-paste competition” across dozens or even hundreds of terminal windows.β€’Inconsistent Environments πŸ˜΅πŸ’«: Network configurations in development, testing, and production environments always have subtle differences, relying on documentation and memory is a disaster. The lack of standardized configurations lays countless hidden dangers for failures.

In the era of cloud and automation,manual network configuration is synonymous with inefficiency and risk. It is not only repetitive labor but also the enemy of stability.

Today, we will end this chaos! This article will guide you in using the Red Hat Ansible Automation Platform (or Community Ansible) to build a modular, precisely controlled <span><span>NetworkManager</span></span> management role, upgrading network configuration from a “manual workshop” to an “automated assembly line”, allowing you to easily handle any scale of network change requirements!✨

✨ The Art of Design: Why We Build Automation This Way?

An excellent automation solution must not only work but also be user-friendly and easy to extend. Our design strictly follows the best practices of enterprise-level automation, with core advantages including:

β€’

Declarative “Final State” Management 🎯 You no longer need to write step-by-step operation scripts. Instead, you only need to declare your desired network final state in a centralized variable file (<span><span>vars/main.yml</span></span>) like filling out a configuration checklistβ€” for example, “I need a connection named<span><span>static-eth1</span></span> with IP xxx and DNS yyy”. Ansible will automatically analyze the differences between the current state and the desired state and execute the necessary operations accurately.

β€’

Functional Modularity and Logical Decoupling 🧩 We split different operations (viewing, adding, modifying, deleting, controlling) into independent task files. The benefits of this approach are:

β€’Single Responsibility: Each file does one thing, making the code logic extremely clear and easy to maintain and debug.β€’Flexible Combination: <span><span>tasks/main.yml</span></span> becomes the master controller, allowing you to enable which functional modules you need like building with Legos.β€’

Precise Execution through Tags surgically is the highlight of this solution! We have tagged each type of operation (<span><span>view</span></span>, <span><span>add</span></span>, <span><span>delete</span></span>, etc.). This means you can fully control the behavior of the Playbook from the command line:

β€’Want to inspect?<span><span>--tags view</span></span><code><span><span>β€’</span></span><span><span>Want to deploy new configurations?</span></span><code><span><span>--tags add,control</span></span><code><span><span>β€’</span></span><span><span>Want to clean up old configurations?</span></span><code><span><span>--tags delete</span></span><code><span><span> This mode transforms Ansible from a "full execution" tool into a Swiss Army knife that can</span></span><strong><span><span>execute on demand and precisely</span></span></strong><span><span>, completely eliminating the risk of misoperation.</span></span><span><span>β€’</span></span><p><span><span>The Ansible Role is applicable to the following operating system versions:</span></span></p><span><span>β€’</span></span><span><span>βœ… Red Hat Enterprise Linux (RHEL) 7, 8, 9</span></span><span><span>β€’</span></span><span><span>βœ… CentOS 7, 8 Stream, 9 Stream</span></span><span><span>β€’</span></span><span><span>βœ… Rocky Linux 8, 9</span></span><span><span>β€’</span></span><span><span>βœ… AlmaLinux 8, 9</span></span><span><span>β€’</span></span><span><span>βœ… Oracle Linux 7, 8, 9</span></span><span><span>β€’</span></span><span><span>βœ… Other modern Linux distributions using NetworkManager as the mainstream network management tool.</span></span><h3><span><span>πŸš€ Getting Started from Scratch: Three Steps to Deploy Your Network Automation Tool</span></span></h3><p><span><span>Don't worry about complexity; I have prepared all the steps for you. You just need to copy and paste to have this powerful tool!</span></span></p><h4><strong><span><span>Prerequisites</span></span></strong><span><span> πŸ“‹</span></span></h4><span><span>β€’</span></span><span><span>πŸ’» </span></span><strong><span><span>Control Node</span></span></strong><span><span>: A computer with Ansible installed.</span></span><span><span>β€’</span></span><span><span>πŸ–₯️ </span></span><strong><span><span>Managed Node</span></span></strong><span><span>: A Linux server with NetworkManager, and the control node can SSH without a password.</span></span><h4><strong><span><span>Step 1: πŸ“ Create and Populate Project Files</span></span></strong></h4><p><span><span>Create the following directory structure and paste the corresponding code blocks into it.</span></span></p><pre><code>network_automation/
β”œβ”€β”€ inventory
β”œβ”€β”€ manage_network.yml
└── roles/
└── networkmanager_cli/
β”œβ”€β”€ tasks/
β”‚ β”œβ”€β”€ main.yml
β”‚ β”œβ”€β”€ view.yml
β”‚ β”œβ”€β”€ add.yml
β”‚ β”œβ”€β”€ control.yml
β”‚ β”œβ”€β”€ modify.yml
β”‚ └── delete.yml
└── vars/
└── main.yml
1

<span><span>inventory</span></span> Example

[rhel]
rhel7.example.com
rhel8.example.com
rhel9.example.com

[rhel7]
Test-RHEL-7.9-1

[net_servers]
server1.example.com
server2.example.com

2

<span><span>manage_network.yml</span></span>

---
- name: Automate NetworkManager Management
  hosts: rhel7
  become: true

  roles:
    - networkmanager_cli

3

<span><span>roles/networkmanager_cli/vars/main.yml</span></span>

β€’Panel Name:⭐️ Main Control Panelβ€’Function Analysis: This is where you issue all commands. Do you want to add, modify, or delete network configurations? What information do you want to view? Just fill in your “battle plan” in this file, and all subsequent automation processes will revolve around your plan.

---
# roles/networkmanager_cli/vars/main.yml
# πŸ’‘ This is the core control file of this Role! Author: FYCheung ([email protected])
# You only need to modify the variables in this file to define all network operations to be executed on the target host.

# Should the "view network information" operation be executed?
# Set to true to view the output of nmcli dev status and nmcli con show.
nm_action_view: true

# --- Add Network Connections ---
# Define all network connections you want to create in this list.
# Ansible will iterate through this list and create them on the target host.
nm_connections_to_add:
  # Example 1: Add a connection with a static IP address
  - name: "static-eth1"      # Network connection name
    ifname: "eth1"            # Bound physical network interface
    type: "ethernet"          # Connection type
    ip4: "192.168.100.50/24"  # IPv4 address and mask
    gw4: "192.168.100.1"      # IPv4 gateway
    method: "manual"          # IP allocation method: manual means static

  # Example 2: Add a DHCP connection
  - name: "dhcp-eth2"
    ifname: "eth2"
    type: "ethernet"
    method: "auto"            # IP allocation method: auto means DHCP

# --- Modify Network Connections ---
# Define the connections you want to modify and their settings in this list.
nm_connections_to_modify:
  # Example: Add DNS servers to the 'static-eth1' connection
  - name: "static-eth1"
    settings:
      # First time setting DNS
      - { key: "ipv4.dns", value: "114.114.114.114" }
      # Use '+' to append a second DNS
      - { key: "+ipv4.dns", value: "8.8.8.8" }

# --- Control Network Connections ---
# Define the list of connection names to be activated (up)
nm_connections_to_activate:
  - static-eth1
  - dhcp-eth2

# Define the list of physical devices to be disabled (disconnect)
nm_devices_to_deactivate:
  #- eth3 # If you need to disable eth3

# --- Delete Network Connections ---
# Define the list of connection names to be deleted
nm_connections_to_delete:
  - old-useless-connection
  - temp-connection

4

<span><span>roles/networkmanager_cli/tasks/main.yml</span></span>

β€’Panel Name:🧠 Intelligent Dispatch Officeβ€’Function Analysis: This is the brain of the automation. It reads your instructions from the “Main Control Panel” and intelligently determines which specific “function panels” need to be called to execute tasks. It is responsible for scheduling and directing, ensuring that each command is accurately conveyed.

---
# roles/networkmanager_cli/tasks/main.yml
# Task master controller - corrected to import_tasks to support tag inheritance

- name: Import - View Network Information Task
  ansible.builtin.import_tasks: view.yml
  when: nm_action_view | bool
  tags: [view]

- name: Import - Add Network Connection Task
  ansible.builtin.import_tasks: add.yml
  when: nm_connections_to_add | length > 0
  tags: [add]

- name: Import - Control Network Connection Task
  ansible.builtin.import_tasks: control.yml
  when: nm_connections_to_activate | length > 0 or nm_devices_to_deactivate | length > 0
  tags: [control]

- name: Import - Modify Network Connection Task
  ansible.builtin.import_tasks: modify.yml
  when: nm_connections_to_modify | length > 0
  tags: [modify]

- name: Import - Delete Network Connection Task
  ansible.builtin.import_tasks: delete.yml
  when: nm_connections_to_delete | length > 0
  tags: [delete]

5

<span><span>roles/networkmanager_cli/tasks/view.yml</span></span>

β€’Panel Name:πŸ“Š Information Dashboardβ€’Function Analysis: When the “Intelligent Dispatch Office” receives the “view” command, this panel is activated. Its sole responsibility is to connect to the server, collect all network status information, and present it clearly to you, just like a car’s dashboard.

---
#
# Module Function: View Network Information
# Control Variable: nm_action_view (set in vars/main.yml)
# Example:
# nm_action_view: true
#
- name: "1.1 View Status of All Network Devices (nmcli dev status)"
  ansible.builtin.command: nmcli dev status
  register: dev_status
  changed_when: false
  failed_when: false

- name: "   -> Display Device Status"
  ansible.builtin.debug:
    var: dev_status.stdout_lines

- name: "1.2 View All Network Connections (nmcli con show)"
  ansible.builtin.command: nmcli con show
  register: con_show
  changed_when: false
  failed_when: false

- name: "   -> Display Connection Information"
  ansible.builtin.debug:
    var: con_show.stdout_lines

6

<span><span>roles/networkmanager_cli/tasks/add.yml</span></span>

β€’Panel Name:πŸ—οΈ Assembly Lineβ€’Function Analysis: Responsible for creating new network connections “from scratch”. Based on the blueprint (IP address, gateway, etc.) you provide in the “Main Control Panel”, this assembly line will automatically assemble standardized network configurations for you.

---
#
# Module Function: Add Network Connection
# Control Variable: nm_connections_to_add (defined in vars/main.yml)
# Example:
# nm_connections_to_add:
#   - name: "static-eth1"
#     ifname: "eth1"
#     type: "ethernet"
#     ip4: "192.168.100.50/24"
#     gw4: "192.168.100.1"
#     method: "manual"
#
- name: "2.1 Loop to Add Specified Network Connections"
  ansible.builtin.command: >
    nmcli con add
    con-name "{{ item.name }}"
    ifname "{{ item.ifname }}"
    type "{{ item.type }}"
    {% if item.method == 'manual' %}
    ipv4.method manual
    ipv4.address "{{ item.ip4 | default('') }}"
    ipv4.gateway "{{ item.gw4 | default('') }}"
    {% else %}
    ipv4.method auto
    {% endif %}
  loop: "{{ nm_connections_to_add }}"
  register: add_result
  changed_when: "'successfully added' in add_result.stdout"

7

<span><span>roles/networkmanager_cli/tasks/modify.yml</span></span>

β€’Panel Name:πŸ”§ Precision Tuning Stationβ€’Function Analysis: Used for fine-tuning existing network connections. Whether it’s changing a DNS or modifying a connection parameter, this “tuning station” can precisely complete the micro-operations, no more, no less, just right.

---
#
# Module Function: Modify Parameters of an Existing Network Connection
# Control Variable: nm_connections_to_modify (defined in vars/main.yml)
# Usage:
#   1. Specify the connection `name` to modify in the list.
#   2. In the `settings` sublist, provide the `key` and `value` to modify.
#      - `key` is the parameter name supported by nmcli (e.g., ipv4.dns, connection.autoconnect).
#      - `value` is the value you want to set.
#      - Use '+' or '-' prefix to append or remove multi-value properties (like DNS).
#
# Example (defined in vars/main.yml):
# nm_connections_to_modify:
#   - name: "static-eth1"
#     settings:
#       - { key: "ipv4.dns", value: "114.114.114.114" }
#       - { key: "+ipv4.dns", value: "8.8.8.8" }
#       - { key: "connection.autoconnect", value: "yes" }
#
- name: "4.1 Loop to Modify Specified Network Connections"
  ansible.builtin.command: "nmcli con mod \"{{ item.0.name }}\" {{ item.1.key }} \"{{ item.1.value }}\""
  with_subelements:
    - "{{ nm_connections_to_modify }}"
    - settings
  loop_control:
    label: "{{ item.0.name }} -> {{ item.1.key }} = {{ item.1.value }}"
  notify: reload_connection # It is recommended to add a handler to reload the connection to make changes effective

8

<span><span>roles/networkmanager_cli/tasks/control.yml</span></span>

β€’Panel Name:🚦 Start/Stop Consoleβ€’Function Analysis: Responsible for controlling the “switch” of network connections. Whether activating a new connection (<span><span>con up</span></span>) or temporarily disconnecting a device (<span><span>dev disconnect</span></span><code><span><span>), this console executes to ensure the connection status is as you wish.</span></span><pre><code>---
#
# Module Function: Activate Network Connection (up) or Disable Network Device (disconnect)
# Control Variables:
# - nm_connections_to_activate (list of connection names)
# - nm_devices_to_deactivate (list of device names, e.g., eth0, ens192)
# Usage:
# Just fill in the names in the corresponding lists.
#
# Example (defined in vars/main.yml):
# nm_connections_to_activate:
# - static-eth1
#
# nm_devices_to_deactivate:
# - eth3
#
- name: "3.1 Activate Specified Network Connections (nmcli con up)"
ansible.builtin.command: "nmcli con up \"{{ item }}\""
loop: "{{ nm_connections_to_activate }}"
register: up_result
changed_when: "'successfully activated' in up_result.stdout"
when: nm_connections_to_activate | length > 0

- name: "3.2 Disable Specified Network Devices (nmcli dev disconnect)"
ansible.builtin.command: "nmcli dev disconnect {{ item }}"
loop: "{{ nm_devices_to_deactivate }}"
register: dis_result
changed_when: "'successfully disconnected' in dis_result.stdout"
when: nm_devices_to_deactivate | length > 0

9

<span><span>roles/networkmanager_cli/tasks/delete.yml</span></span>

β€’Panel Name:♻️ Recycling & Cleanup Stationβ€’Function Analysis: This panel activates when you need to clean up unused network configurations. It safely and thoroughly removes the old connections you specify, keeping your server configuration tidy.

---
#
# Module Function: Delete One or More Network Connections
# Control Variable: nm_connections_to_delete (defined in vars/main.yml)
# Usage:
#   Just fill in the names of the connections you want to delete in the list.
#
# Example (defined in vars/main.yml):
# nm_connections_to_delete:
#   - old-connection-1
#   - temp-for-test
#
- name: "5.1 Loop to Delete Specified Network Connections"
  ansible.builtin.command: "nmcli con del \"{{ item }}\""
  loop: "{{ nm_connections_to_delete }}"
  register: del_result
  changed_when: "'successfully deleted' in del_result.stdout"
  failed_when: del_result.rc != 0 and 'not found' not in del_result.stderr

β€’<span><span>manage_network.yml (emphasizing this</span></span><span><span> file)</span></span>β€’Panel Name:πŸ”΄ The Big Red Buttonβ€’Function Analysis: This is the only entry point for the entire automation process. Once you set all instructions in the “Main Control Panel”, just press this “Big Red Button” (i.e., run <span><span>ansible-playbook manage_network.yml</span></span> command), and the “Intelligent Dispatch Office” will immediately start working, directing all function panels to work together to complete all the tasks you deployed!

Step 2: ✍️ Issue Commands in the “Main Control Panel”

This is the most exciting part! All your network change requirements only need to modify the one file <span><span>roles/networkmanager_cli/vars/main.yml</span></span>, which is your “battle plan”.

Let’s look at a real customer scenario: Suppose you need to configure <span><span>Test-RHEL-7.9-1</span></span> with the following requirements:

1 Configure a <span><span>static IP</span></span> for its <span><span>eth1</span></span> interface.2 Configure a <span><span>DHCP</span></span> connection for its <span><span>eth2</span></span> interface.3 Clean up an old connection named <span><span>old-temp-config</span></span><span><span> .</span></span><p><span><span>We just need to open the "Main Control Panel" </span></span><code><span><span>roles/networkmanager_cli/vars/main.yml</span></span>, and fill in our intentions like filling out a checklist:

---
# roles/networkmanager_cli/vars/main.yml
# πŸ’‘ This is the core control file of this Role! Author: FYCheung ([email protected])

# For this operation, we will not view information, focusing on changes
nm_action_view: false

# --- Add Network Connections ---
# Define the two connections we need to create
nm_connections_to_add:
  # Requirement 1: Add static IP for eth1
  - name: "static-eth1-prod"
    ifname: "eth1"            # ❗️Note: Ensure the interface name here matches your server!
    type: "ethernet"
    ip4: "192.168.100.50/24"
    gw4: "192.168.100.1"
    method: "manual"

  # Requirement 2: Add DHCP for eth2
  - name: "dhcp-eth2-prod"
    ifname: "eth2"            # ❗️Note: Ensure the interface name here matches your server!
    type: "ethernet"
    method: "auto"

# --- Modify Network Connections ---
# This operation does not modify, keep it empty
nm_connections_to_modify: []

# --- Control Network Connections ---
# After adding, we need to activate these two new connections
nm_connections_to_activate:
  - static-eth1-prod
  - dhcp-eth2-prod

# This operation does not disable devices, keep it empty
nm_devices_to_deactivate: []

# --- Delete Network Connections ---
# Requirement 3: Clean up an old connection
nm_connections_to_delete:
  - old-temp-config

🀩 Do you see it? We didn’t write a single line of command, we justdeclared our desired network state. This is the charm of Ansible!

Step 3: πŸš€ Precise Execution!

The “battle plan” has been formulated, and now it’s time to press the “Big Red Button” <span><span>manage_network.yml</span></span>. With the tag (Tags) feature we designed earlier, we can execute each step in the plan precisely like performing surgery.

In your <span><span>network_automation</span></span> directory, open a terminal and start your automation performance!

β€’

Step One: First, inspect the network status to ensure everything is in order

# Use -t view parameter to only run the view task
ansible-playbook manage_network.yml -i inventory -t view

β€’

Step Two: Execute add and activate tasks

# Use comma to combine tags, executing add and control tasks simultaneously
ansible-playbook manage_network.yml -i inventory -t add,control

β€’

Step Three: Execute cleanup tasks

# Execute delete task separately
ansible-playbook manage_network.yml -i inventory -t delete

πŸ’‘ Your Exclusive Command Memo

Your Intent Execution Command
Just want to view without making changes, safe inspection ansible-playbook manage_network.yml -i inventory -t view
Only responsible for creating new connections ansible-playbook manage_network.yml -i inventory -t add
Only responsible for modifying existing connections ansible-playbook manage_network.yml -i inventory -t modify
Only responsible for starting/stopping connections/devices ansible-playbook manage_network.yml -i inventory -t control
Only responsible for deleting old connections ansible-playbook manage_network.yml -i inventory -t delete
Combination! Execute simultaneously ansible-playbook manage_network.yml -i inventory -t add,delete, view

Summary and Resources

With this carefully designed Ansible Role, you now have a powerful, flexible, and easy-to-use network automation tool. It will help you say goodbye to repetition and risk, embracing standardization and high efficiency.

Are you eager to deploy it in your environment?

To avoid any omissions that may occur while copying the code, we have packaged the complete project containingall categorized and filled code for you!

🎁 Click the link below to 【Read the Original】 and download the complete source code, adding another Swiss Army knife to your operations toolbox!πŸ‘‡πŸ‘‡πŸ‘‡

Leave a Comment