Mastering Network Automation with the Ansible cisco.ios.ios_command Module

The automation of network infrastructure has transitioned from a luxury to a necessity for modern enterprise environments. At the heart of this transition for Cisco environments is the cisco.ios.ios_command module, a powerful tool within the cisco.ios collection designed to execute operational commands on Cisco IOS and IOS XE devices. Unlike configuration modules that push changes, the ios_command module is primarily used for gathering state, verifying configurations, and performing read-only operations. By leveraging this module, network engineers can move away from the error-prone process of manually SSHing into dozens of switches and routers, replacing it with a programmatic, repeatable, and auditable workflow. This capability is essential for maintaining the stability of the network backbone, from branch office routers to campus switches, ensuring that operational data is collected consistently across the entire fleet.

Foundations of the cisco.ios Collection

To utilize the ios_command module, one must first integrate the cisco.ios collection into the Ansible environment. This collection is a dedicated set of content specifically developed to manage Cisco IOS and IOS XE network appliances. For those utilizing Cisco Modeling Labs (CML), the collection has been rigorously tested against Cisco IOS XE Version 17.3, ensuring compatibility with modern virtualized network environments.

The technical requirement for running these modules involves ensuring that the Ansible version is 2.16.0 or greater. This versioning constraint is critical because the modules rely on specific PEP440 schema descriptions for versioning and depend on the network_cli connection plugin. The network_cli connection is the primary mechanism by which Ansible communicates with the device, simulating a terminal session to send commands and receive output.

To install the necessary components, the following command must be executed in the terminal:

ansible-galaxy collection install cisco.ios

The infrastructure for this automation requires a properly defined inventory file. A typical setup involves grouping devices into functional categories, such as routers and switches, and defining global variables that govern how Ansible interacts with the IOS shell.

Example inventory configuration:

```ini
[iosrouters]
rtr-core-01 ansible
host=10.0.0.1
rtr-core-02 ansiblehost=10.0.0.2
rtr-branch-01 ansible
host=10.0.10.1

[iosswitches]
sw-access-01 ansible
host=10.0.1.1
sw-access-02 ansiblehost=10.0.1.2
sw-dist-01 ansible
host=10.0.1.10

[ios:children]
iosrouters
ios
switches

[ios:vars]
ansiblenetworkos=cisco.ios.ios
ansibleconnection=ansible.netcommon.networkcli
ansibleuser=admin
ansible
password={{ vaultiospassword }}
ansiblebecome=yes
ansible
becomemethod=enable
ansible
becomepassword={{ vaultenable_password }}
```

The use of ansible_become and ansible_become_method=enable is a critical technical requirement. In Cisco IOS, most operational and configuration commands require privileged EXEC mode. By setting these variables, Ansible automatically handles the enable command and the subsequent password prompt, granting the playbook the necessary permissions to execute high-level commands.

Deep Dive into the ios_command Module

The cisco.ios.ios_command module is designed to send a list of commands to a Cisco device and return the output. While it is often used for simple show commands, its true power lies in its ability to be used for verification and compliance auditing.

Technical Parameter Analysis

The module provides several parameters to control the execution and flow of commands:

  • commands: This is the primary input, consisting of a list of strings. Each string is a command that will be executed on the device.
  • authorize: This parameter (often used in older versions or specific contexts) determines if the module should enter privileged mode. When set to yes, it ensures the session is elevated.
  • waitfor: This is a sophisticated parameter used to pause the playbook until a specific condition is met in the output. This prevents the playbook from progressing until the device has reached a desired state.
  • prompt: Some IOS commands, such as crypto key generate rsa, trigger interactive confirmation prompts. The prompt parameter allows the module to recognize these prompts and respond accordingly, preventing the playbook from hanging.

The Verification Workflow

A common pattern in network automation is the "Configure-Verify-Save" cycle. The ios_command module is the essential "Verify" component of this cycle. For instance, if a network engineer uses the ios_config module to apply an Access Control List (ACL), they should not simply assume the command was successful. Instead, they use ios_command to run a show access-lists command and verify the presence of the specific rule.

Consider the following implementation for ACL verification:

yaml - name: Verify ACL is present ios_command: commands: - sh access-l waitfor: - result[0] contains 'permit 172.16.1.100'

In this scenario, the waitfor parameter acts as a gatekeeper. The playbook will not proceed to the next task until the output of the first command (result[0]) contains the specific string 'permit 172.16.1.100'. This ensures that the configuration is actually active in the running config before the engineer proceeds to save the changes.

Compliance Auditing and State Validation

The ios_command module is the primary engine for security compliance. By registering the output of a show running-config command, an engineer can use the ansible.builtin.assert module to validate that the device meets organizational security standards.

The process involves three technical layers:
1. Execution: Running the command via ios_command.
2. Registration: Saving the output into a variable using the register keyword.
3. Assertion: Testing the variable for the presence of required configuration strings.

Example compliance playbook:

```yaml
- name: Check IOS compliance
hosts: ios
gatherfacts: no
tasks:
- name: Gather current configuration
cisco.ios.ios
command:
commands:
- show running-config
register: running_config

- name: Check SSH version 2 is enabled
  ansible.builtin.assert:
    that:
      - "'ip ssh version 2' in running_config.stdout[0]"
    fail_msg: "SSH version 2 is NOT enabled on {{ inventory_hostname }}"
    success_msg: "SSH version 2 is enabled"

- name: Check password encryption is enabled
  ansible.builtin.assert:
    that:
      - "'service password-encryption' in running_config.stdout[0]"
    fail_msg: "Password encryption is NOT enabled on {{ inventory_hostname }}"
    success_msg: "Password encryption is enabled"

- name: Check NTP is configured
  ansible.builtin.assert:
    that:
      - "'ntp server' in running_config.stdout[0]"
    fail_msg: "NTP is NOT configured on {{ inventory_hostname }}"
    success_msg: "NTP is configured"

- name: Check telnet is disabled on VTY lines
  ansible.builtin.assert:
    that:
      - "'transport input ssh' in running_config.stdout[0]"
    fail_msg: "Telnet may still be enabled on {{ inventory_hostname }}"
    success_msg: "Transport input is SSH-only"

```

This approach transforms the ios_command module from a simple "command runner" into a powerful auditing tool. By utilizing the stdout[0] index of the registered variable, Ansible can parse the raw text of the Cisco configuration to ensure that critical security features, such as SSH version 2 and password encryption, are active. This provides a high level of visibility and ensures that no device in the infrastructure deviates from the security baseline.

Integration with iosconfig and iosfacts

To achieve absolute exhaustion of the Cisco IOS automation ecosystem, one must understand how ios_command interacts with its sibling modules.

The ios_config Module

While ios_command is for reading and verifying, ios_config is the workhorse for modification. It automatically handles the transition into configure terminal mode and the subsequent end command. A critical aspect of using ios_config is managing the persistence of changes. Because IOS devices maintain a running configuration (RAM) and a startup configuration (NVRAM), changes are lost upon reboot unless saved.

The save parameter in ios_config allows the user to commit changes to the startup config. In older versions of Ansible (such as 2.3), a simple save: yes was used. However, starting with version 2.4, the save_when parameter was introduced. This allows for more granular control:

  • modified: The configuration is saved only if changes were actually made. This is the recommended best practice to avoid unnecessary writes to the NVRAM.
  • always: The configuration is saved regardless of whether changes occurred.
  • never: The configuration is never saved.

Example of an integrated configuration and save workflow:

```yaml
- name: Configure ACL on Cisco Switch
ios_config:
authorize: yes
lines:
- access-list 99 permit 172.16.1.100

  • name: Verify ACL is present
    ios_command:
    commands:
    - sh access-l
    waitfor:
    - result[0] contains 'permit 172.16.1.100'

  • name: SAVE CONFIG
    ios_config:
    authorize: yes
    save: yes
    ```

The ios_facts Module

The cisco.ios.ios_facts module provides structured data about the device, which can be used to make conditional decisions before running an ios_command. Instead of parsing raw text, ios_facts collects hardware, software, and interface information into a structured format.

Example of gathering and displaying device facts:

```yaml
- name: Gather Cisco IOS facts
hosts: ios
gatherfacts: no
tasks:
- name: Collect all available facts
cisco.ios.ios
facts:
gather_subset:
- all
register: facts

- name: Display device summary
  ansible.builtin.debug:
    msg: |
      Device: {{ ansible_net_hostname }}
      Model: {{ ansible_net_model }}
      IOS Version: {{ ansible_net_version }}
      Serial Number: {{ ansible_net_serialnum }}
      Image: {{ ansible_net_image }}

- name: List all interfaces
  ansible.builtin.debug:
    msg: "{{ ansible_net_interfaces | dict2items | map(attribute='key') | list }}"

```

By combining ios_facts (to identify the device), ios_config (to change the device), and ios_command (to verify the change), an engineer creates a complete closed-loop automation system.

Advanced Operational Strategies

For professional-grade deployments, simply running a playbook is insufficient. High-reliability environments require specific strategies to ensure that automation does not cause widespread outages.

The Use of Resource Modules

While ios_config is versatile, it is often better to use resource modules such as ios_interfaces, ios_vlans, and ios_acls. These modules provide a declarative approach, meaning they focus on the "state" of the resource rather than the "commands" used to create it. For settings that do not have a dedicated resource module, ios_config remains the fallback.

Testing with Check and Diff

One of the most valuable features of the Cisco IOS modules is the ability to test changes before they are applied. By using the --check and --diff flags during playbook execution, Ansible will simulate the changes.

  • --check: This tells Ansible to run in "dry run" mode. It will report if a change would have been made without actually executing it.
  • --diff: When combined with --check, the diff output shows the exact lines that would be added or removed from the configuration.

This process is critical for reviewing changes in a staging environment or performing a peer review of a network change before it hits the production core.

Comparison of Cisco IOS Modules

The following table provides a technical comparison of the primary modules used in Cisco IOS automation.

Module Primary Purpose Mode of Operation Key Parameters Typical Use Case
ios_command Operational Data Read-only / Execution commands, waitfor, prompt Verifying ACLs, Compliance Audits
ios_config Configuration Management Read-Write lines, save_when, authorize Pushing Banners, Creating ACLs
ios_facts State Discovery Read-only gather_subset Inventorying Hardware, Version Checks
ios_acls Resource Management Declarative config Managing ACLs as structured data

Conclusion

The cisco.ios.ios_command module is far more than a tool for executing show commands; it is the foundational element for verification and compliance within the Cisco IOS ecosystem. By integrating this module into a broader strategy that includes ios_config for changes and ios_facts for device discovery, network engineers can achieve a level of rigor and repeatability previously reserved for server infrastructure. The transition to this model minimizes the risk of human error, accelerates the deployment of security patches, and ensures that the network remains in a known, compliant state. Through the use of waitfor conditions, privileged mode authorization via ansible_become, and the verification of output through assertions, the ios_command module enables the creation of safe, auditable, and scalable network automation pipelines.

Sources

  1. Roger Perkin - Ansible IOS_Command Example
  2. OneUptime - How to use Ansible with Cisco IOS Devices
  3. GitHub - ansible-collections/cisco.ios

Related Posts