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 FQCN Error: Fix Fully Qualified Collection Name Issues (Guide)

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

Fix Ansible FQCN errors. Understand Fully Qualified Collection Names, migrate from short module names, resolve 'could not resolve module' errors.

Ansible FQCN Error: Fix Fully Qualified Collection Name Issues (Guide)

Using Fully-Qualified Collection Names (FQCN) in Ansible Content

In the world of automation and orchestration, Ansible has established itself as a popular choice for managing IT infrastructure and application deployments. Ansible allows you to create powerful automation scripts, or playbooks, to streamline tasks and manage resources efficiently. However, as with any coding or scripting language, adhering to best practices is essential for maintaining code quality and avoiding potential pitfalls. This article focuses on a specific Ansible linting rule called "fqcn," which checks for fully-qualified collection names (FQCN) in Ansible content.

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

What Is FQCN?

A Fully-Qualified Collection Name, or FQCN for short, is a way to specify the full namespace for an Ansible module or action. It serves the purpose of eliminating ambiguity and ensuring that the correct code from the correct collection is executed. In the context of Ansible, collections refer to reusable packages of playbooks, roles, modules, and other components that help streamline automation tasks.

The "fqcn" rule helps maintain code quality by ensuring that you use FQCNs for module actions. This rule offers several checks, including: • fqcn[action]: Encourages the use of FQCN for module actions. • fqcn[action-core]: Checks for FQCNs from the ansible.legacy or ansible.builtin collection. • fqcn[canonical]: Promotes the use of canonical module names over aliases or redirects. • fqcn[deep]: Discourages deep/nested plugins directories within collections. • fqcn[keyword]: Advises against using the "collections" keyword by using FQCN for all plugins, modules, roles, and playbooks.

Canonical Module Names

Canonical module names, also known as resolved module names, are the preferred way to refer to Ansible modules. Many Ansible modules have multiple aliases and redirects that were created over time as the content evolved. However, all these aliases eventually resolve to the same module name. By using canonical names, you can simplify your code and avoid performance overhead.

The only exception to using canonical names is when your code needs to be compatible with very old Ansible versions that do not recognize these names. In such cases, you can exclude this rule from the linter's checks.

Note: Ansible provides an option to automatically fix for a selection of modules for the "fqcn" error using the ansible-lint --fix option, which can be a helpful tool in resolving this issue in your playbooks.

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

Avoid Deep Modules

Starting in early 2023, the official guidance from Ansible's core team is to avoid nesting modules in deep directories. It's recommended to use a flat directory structure for modules, as it ensures optimal performance. Existing collections that use deep directories can migrate to the flat structure in a backward-compatible way by adding redirects.

Problematic Code and Correct Solutions

Let's look at some examples of problematic code and how to correct them:

Problematic Code

---
- name: Example playbook
  hosts: all
  tasks:
    - name: Create an SSH connection
      shell: ssh ssh_user@{{ ansible_ssh_host }}

The above code does not use FQCN for the shell module.

Output

WARNING  Listing 3 violation(s) that are fatal
command-instead-of-shell: Use shell only when shell functionality is required.
fqcn.yml:5 Task/Handler: Create an SSH connection

fqcn[action-core]: Use FQCN for builtin module actions (shell). fqcn.yml:5 Use `ansible.builtin.shell` or `ansible.legacy.shell` instead.

no-changed-when: Commands should not change things if nothing needs doing. fqcn.yml:5 Task/Handler: Create an SSH connection

Read documentation for instructions on how to ignore specific rule violations.

Rule Violation Summary count tag profile rule associated tags 1 command-instead-of-shell basic command-shell, idiom 1 no-changed-when shared command-shell, idempotency 1 fqcn[action-core] production formatting

Failed: 3 failure(s), 0 warning(s) on 1 files. Last profile that met the validation criteria was 'min'.

Correct Code (1st Solution)

---
- name: Example playbook (1st solution)
  hosts: all
  tasks:
    - name: Create an SSH connection
      ansible.legacy.shell:
        ssh ssh_user@{{ ansible_ssh_host }} -o IdentityFile=path/to/my_rsa

In this solution, the FQCN for the legacy shell module is used, allowing local overrides.

Correct Code (2nd Solution)

---
- name: Example playbook (2nd solution)
  hosts: all
  tasks:
    - name: Create an SSH connection
      ansible.builtin.shell: ssh ssh_user@{{ ansible_ssh_host }}

This solution uses the FQCN for the builtin shell module.

By using FQCNs, you ensure that your code references the correct collection and module, reducing the chances of ambiguity and conflicts.

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

Conclusion

The "fqcn" Ansible linting rule is a valuable tool for ensuring code quality in your Ansible content. By adhering to FQCN best practices, you can prevent potential issues and maintain consistent and efficient automation scripts. Following Ansible's recommended guidelines for using canonical module names and avoiding deep module directories can help you write cleaner, more performant automation code.

The Error

fqcn[action-core]: Use FQCN for builtin module actions (copy).
fqcn[action]: Use FQCN for module actions (community.general.timezone).

Quick Fix

# WRONG — short name
- copy:
    src: file.txt
    dest: /tmp/file.txt

# CORRECT — FQCN - ansible.builtin.copy: src: file.txt dest: /tmp/file.txt

Common Conversions

# Before (short names)          # After (FQCN)
- apt:                           - ansible.builtin.apt:
- yum:                           - ansible.builtin.yum:
- copy:                          - ansible.builtin.copy:
- template:                      - ansible.builtin.template:
- file:                          - ansible.builtin.file:
- service:                       - ansible.builtin.service:
- systemd:                       - ansible.builtin.systemd:
- command:                       - ansible.builtin.command:
- shell:                         - ansible.builtin.shell:
- debug:                         - ansible.builtin.debug:
- user:                          - ansible.builtin.user:
- group:                         - ansible.builtin.group:
- lineinfile:                    - ansible.builtin.lineinfile:
- stat:                          - ansible.builtin.stat:
- uri:                           - ansible.builtin.uri:
- get_url:                       - ansible.builtin.get_url:
- set_fact:                      - ansible.builtin.set_fact:
- assert:                        - ansible.builtin.assert:
- include_role:                  - ansible.builtin.include_role:
- include_tasks:                 - ansible.builtin.include_tasks:
- import_tasks:                  - ansible.builtin.import_tasks:
- setup:                         - ansible.builtin.setup:
- ping:                          - ansible.builtin.ping:
- wait_for:                      - ansible.builtin.wait_for:
- reboot:                        - ansible.builtin.reboot:

Community Module FQCNs

# These need their collection FQCN
- community.general.timezone:
- community.general.ufw:
- community.docker.docker_container:
- community.mysql.mysql_db:
- ansible.posix.sysctl:
- ansible.posix.mount:
- amazon.aws.ec2_instance:
- ansible.windows.win_copy:

Automated Migration

# Find all short names in your project
grep -rn '^\s*- \(copy\|template\|file\|service\|command\|shell\|debug\|apt\|yum\|user\|group\):' roles/

# Use sed for bulk replacement find . -name "*.yml" -exec sed -i \ -e 's/^\(\s*\)- copy:/\1- ansible.builtin.copy:/g' \ -e 's/^\(\s*\)- template:/\1- ansible.builtin.template:/g' \ -e 's/^\(\s*\)- file:/\1- ansible.builtin.file:/g' \ -e 's/^\(\s*\)- service:/\1- ansible.builtin.service:/g' \ {} \;

Configure ansible-lint

# .ansible-lint
skip_list:
  # Skip FQCN rules (not recommended)
  - fqcn[action-core]
  - fqcn[action]

# Or warn instead of error warn_list: - fqcn[action-core]

FQCN Rule Variants

| Rule | Description | |------|-------------| | fqcn[action-core] | Built-in modules need ansible.builtin. | | fqcn[action] | All modules need FQCN | | fqcn[canonical] | Use canonical FQCN (not redirects) |

Why FQCN Matters

Explicit — no ambiguity about which module is used Future-proof — short names may conflict with custom modules Collection-aware — works correctly with collection routing Best practice — recommended since Ansible 2.10+

FAQ

Do I have to use FQCN everywhere?

It's strongly recommended but not required. Short names still work. ansible-lint enforces FQCN as a best practice.

What about action plugins like block/rescue?

block, rescue, always, when, loop, register are Ansible keywords, not modules. They don't need FQCN.

FQCN makes playbooks verbose — any shortcut?

Use collections: keyword at play level:

- hosts: all
  collections:
    - ansible.builtin
    - community.general
  tasks:
    - copy: ...  # Resolves to ansible.builtin.copy
Note: ansible-lint may still flag this.

The Error

fqcn[action-core]: Use FQCN for builtin module actions (copy).
fqcn[action]: Use FQCN for module actions, such `community.general.ufw`.

Quick Fix

# WRONG — short name
- copy:
    src: file.txt
    dest: /tmp/file.txt

# CORRECT — FQCN - ansible.builtin.copy: src: file.txt dest: /tmp/file.txt

Common FQCN Replacements

# Core modules
copy          → ansible.builtin.copy
file          → ansible.builtin.file
template      → ansible.builtin.template
command       → ansible.builtin.command
shell         → ansible.builtin.shell
apt           → ansible.builtin.apt
yum           → ansible.builtin.yum
dnf           → ansible.builtin.dnf
service       → ansible.builtin.service
systemd       → ansible.builtin.systemd
user          → ansible.builtin.user
group         → ansible.builtin.group
debug         → ansible.builtin.debug
set_fact      → ansible.builtin.set_fact
assert        → ansible.builtin.assert
include_role  → ansible.builtin.include_role
import_tasks  → ansible.builtin.import_tasks
ping          → ansible.builtin.ping
setup         → ansible.builtin.setup
stat          → ansible.builtin.stat
uri           → ansible.builtin.uri
get_url       → ansible.builtin.get_url
lineinfile    → ansible.builtin.lineinfile
blockinfile   → ansible.builtin.blockinfile
cron          → ansible.builtin.cron
unarchive     → ansible.builtin.unarchive

Community Modules

ufw           → community.general.ufw
docker_container → community.docker.docker_container
ec2_instance  → amazon.aws.ec2_instance
azure_rm_*    → azure.azcollection.azure_rm_*

Find FQCN for Any Module

# Search installed collections
ansible-doc -l | grep copy
# ansible.builtin.copy

ansible-doc ansible.builtin.copy

Bulk Fix with sed

# Example: fix common modules
sed -i 's/^  copy:/  ansible.builtin.copy:/g' playbook.yml
sed -i 's/^  file:/  ansible.builtin.file:/g' playbook.yml

Skip the Rule

# Per task (not recommended)
- copy:  # noqa: fqcn[action-core]
    src: file.txt
    dest: /tmp/

# Globally in .ansible-lint skip_list: - fqcn[action-core]

FAQ

Why use FQCN?

Prevents name collisions between collections. If two collections define a copy module, FQCN ensures you get the right one.

Does FQCN change behavior?

No — ansible.builtin.copy and copy do exactly the same thing. It's about explicitness and future-proofing.

Do I need FQCN for roles?

Yes for collection roles: myorg.mycollection.myrole. Regular roles in roles/ don't need it.

Related Articles

multi-condition Ansible when clausesrole dependencies in AnsibleAnsible handlers guide

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home