AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible-Lint Error 302 deprecated-command-syntax: Fix Guide

By Luca Berton · Published 2024-01-01 · Category: installation

Fix ansible-lint Error 302 deprecated-command-syntax. Replace command/shell with proper Ansible modules for file operations, package management, and services.

Ansible-Lint Error 302 deprecated-command-syntax: Fix Guide

Introduction

Ansible, the versatile automation platform, simplifies the process of automating tasks, managing configurations, and orchestrating complex processes. While Ansible provides flexibility, it's important to adhere to best practices to ensure the maintainability and readability of your playbooks. In this article, we'll explore Ansible Error 302, "deprecated-command-syntax," in Ansible-Lint which focuses on discouraging the use of shorthand or free-form syntax within playbooks. We'll discuss why this syntax is discouraged and provide examples of how to use the correct, more structured syntax in your Ansible playbooks.

See also: Ansible troubleshooting - Error 102: No Jinja2 in 'when' Conditions

The Problem: Deprecated Command Syntax

Ansible Error 302, "deprecated-command-syntax," is designed to identify the use of shorthand or free-form syntax within Ansible playbooks. While using shorthand syntax from the command line is acceptable, it is highly discouraged when used inside playbooks. This is because shorthand syntax can easily lead to bugs that are hard to identify, impacting the readability and maintainability of your automation tasks.

Problematic Code Example:

---
- name: Example playbook
  hosts: all
  tasks:
    - name: Perform chmod
      ansible.builtin.command: creates=B chmod 644 A # <-- do not use shorthand

In the problematic code above, the shorthand syntax is used within the ansible.builtin.command module, making it less readable and potentially prone to errors.

Correcting Deprecated Command Syntax

To address Ansible Error 302 and ensure the use of structured, non-shorthand syntax within playbooks, you should reformat the code as follows:

---
- name: Example playbook
  hosts: all
  tasks:
    - name: Perform chmod
      ansible.builtin.command: chmod 644 A
      args:
        creates: B

In the corrected code, the structured syntax is used within the ansible.builtin.command module, making the playbook more readable and maintainable. Additionally, the args section is used to specify the creates argument, providing a clear separation of parameters.

See also: Ansible troubleshooting - Error 104: Deprecated Bare Vars

Benefits of Eliminating Deprecated Command Syntax

Improved Readability: Structured syntax makes your Ansible playbooks more readable and understandable, reducing the likelihood of errors. Easier Troubleshooting: Eliminating shorthand syntax minimizes the potential for bugs that are challenging to identify and resolve. Consistency: Using consistent, structured syntax in your playbooks fosters a standardized and clean codebase. Adherence to Best Practices: Following best practices for playbook syntax aligns with Ansible guidelines, ensuring the reliability of your automation tasks.

Conclusion

Ansible Error 302, "deprecated-command-syntax," underlines the importance of using structured, non-shorthand syntax within Ansible playbooks. By adhering to this rule, you can significantly enhance the readability, maintainability, and reliability of your automation tasks.

In the world of automation, adherence to best practices is paramount to achieve consistent, error-free results. So, when working with Ansible, make it a practice to eliminate deprecated command syntax in your playbooks, and enjoy cleaner, more dependable automation.

See also: Ansible troubleshooting - Error 105: Deprecated Module Usage

The Error

[302] Deprecated command syntax: Instead of using free-form with the command module, use cmd parameter.

Fix: Use cmd Parameter

Before (deprecated)

# Free-form syntax (deprecated)
- command: cat /etc/hostname
- shell: echo $HOME | tee /tmp/home.txt

After (correct)

# Explicit cmd parameter
- ansible.builtin.command:
    cmd: cat /etc/hostname

- ansible.builtin.shell: cmd: echo $HOME | tee /tmp/home.txt

Common Migrations

command module

# OLD
- command: systemctl restart nginx
- command: mkdir -p /opt/myapp

# NEW - ansible.builtin.command: cmd: systemctl restart nginx

- ansible.builtin.command: cmd: mkdir -p /opt/myapp creates: /opt/myapp

shell module

# OLD
- shell: ps aux | grep nginx | grep -v grep

# NEW - ansible.builtin.shell: cmd: ps aux | grep nginx | grep -v grep changed_when: false

With chdir and creates

# OLD
- command: make install
  args:
    chdir: /opt/myapp
    creates: /usr/local/bin/myapp

# NEW - ansible.builtin.command: cmd: make install chdir: /opt/myapp creates: /usr/local/bin/myapp

Better: Use Purpose-Built Modules

# Instead of: command: systemctl restart nginx
- ansible.builtin.service:
    name: nginx
    state: restarted

# Instead of: command: mkdir -p /opt/myapp - ansible.builtin.file: path: /opt/myapp state: directory

# Instead of: command: useradd deploy - ansible.builtin.user: name: deploy state: present

# Instead of: shell: apt install -y nginx - ansible.builtin.apt: name: nginx state: present

Lint Configuration

# .ansible-lint
skip_list:
  - '302'  # Skip if you need free-form temporarily

warn_list: - '302' # Warn instead of error

FAQ

Why was free-form deprecated?

Free-form syntax is ambiguous — Ansible can't distinguish between command arguments and module parameters. Explicit cmd: is clearer and less error-prone.

Does this affect ad-hoc commands?

No — ad-hoc commands (ansible all -m command -a "uptime") use -a which is different from playbook free-form syntax.

Will free-form stop working?

Not immediately, but it generates warnings/errors with ansible-lint and may be removed in future Ansible versions. Migrate now.

The Error

[deprecated-command-syntax] Command 'chown' used in place of module.
[deprecated-command-syntax] Command 'chmod' used in place of module.
[deprecated-command-syntax] Command 'mkdir' used in place of module.

Quick Fixes

File Operations

# WRONG — using shell commands
- command: mkdir -p /opt/myapp
- command: chmod 755 /opt/myapp
- command: chown deploy:deploy /opt/myapp

# CORRECT — use file module - ansible.builtin.file: path: /opt/myapp state: directory mode: '0755' owner: deploy group: deploy become: true

Package Management

# WRONG
- command: apt-get install -y nginx
- command: yum install -y httpd

# CORRECT - ansible.builtin.apt: name: nginx state: present become: true

- ansible.builtin.yum: name: httpd state: present become: true

Service Management

# WRONG
- command: systemctl restart nginx
- command: service httpd start

# CORRECT - ansible.builtin.systemd: name: nginx state: restarted become: true

- ansible.builtin.service: name: httpd state: started become: true

User Management

# WRONG
- command: useradd -m deploy

# CORRECT - ansible.builtin.user: name: deploy create_home: true become: true

Complete Conversion Table

| Shell Command | Ansible Module | |--------------|---------------| | mkdir | file: state=directory | | rm / rmdir | file: state=absent | | chmod | file: mode= | | chown | file: owner= group= | | cp | copy: | | mv | command: mv (no module) | | ln -s | file: state=link | | apt-get | apt: | | yum | yum: | | dnf | dnf: | | pip | pip: | | systemctl | systemd: | | service | service: | | useradd | user: | | groupadd | group: | | mount | ansible.posix.mount: | | sysctl | ansible.posix.sysctl: | | curl/wget | get_url: or uri: | | tar/unzip | unarchive: | | sed | lineinfile: or replace: |

When command/shell IS Appropriate

# Custom scripts with no module equivalent
- ansible.builtin.command:
    cmd: /opt/myapp/migrate-db.sh
  changed_when: false

# Complex pipelines - ansible.builtin.shell: cmd: ps aux | grep nginx | grep -v grep | wc -l register: nginx_count changed_when: false

Suppress the Warning

# .ansible-lint
skip_list:
  - deprecated-command-syntax  # Not recommended

# Better: fix per-task warn_list: - deprecated-command-syntax

FAQ

Why does this rule exist?

Ansible modules are idempotent (safe to run multiple times), provide proper change tracking, and work across platforms. Raw commands don't.

What about mv — there's no module?

There's no move module. Use command: mv or combine copy + file: state=absent. The lint rule only flags commands that have module equivalents.

Does this affect playbook execution?

No — it's a linting rule only. Shell commands still work fine, but modules are the recommended approach.

Related Articles

Ansible when conditional guide

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home