unit 1 · Orientation

Collections & FQCN

Why old tutorials lie to you

essential · 6 min · linux + windows

you may want to read 3 · ansible-core vs the community package first — but nothing is locked

tl;dr

  • Since Ansible 2.10, modules live in collections — versioned packages under a namespace.
  • FQCN is the full path: ansible.builtin.copy, not copy. Write it always.
  • Old tutorials use bare names because they predate the split. That is how you date them.

why it matters Half the Ansible answers on the internet predate collections; if you can’t spot pre-2.10 content, you’ll copy patterns your linter rejects and your colleagues left behind years ago.

Up to Ansible 2.9, every module shipped in one monolithic package — three thousand–plus modules, all versioned together, all released together. Ansible

2.10 broke that monolith into collections: independently versioned packages, each owning its modules, roles and plugins under a namespace. The community package you met in the last lesson is really ansible-core plus 85+ curated collections.

That split created the FQCN — the full path to a module:

- name: Push the MOTD file
  ansible.builtin.copy:
    src: files/motd
    dest: /etc/motd
namespace . collection . module

Read it right-to-left: the copy module, in the builtin collection, published under the ansible namespace . Three other FQCNs you’ll meet constantly: ansible.builtin.service, community.general.ufw, ansible.windows.win_copy — that last pair matters for your estate, because Linux and Windows modules live in entirely different collections.

Why old tutorials lie to you

Most tutorials, blog posts and Stack Overflow answers predate the split. They write bare module names, because before 2.10 that’s all there was:

old — don't write this · pre-2.10 style — bare names
- name: Push the MOTD file
  copy:
    src: files/motd
    dest: /etc/motd

Here’s the trap: that still runs. Modules that existed in the 2.9 era keep resolving through a redirect mapping, so old playbooks didn’t break. Which means bare names don’t fail loudly — they just quietly mark your YAML as dated, and they set you up for two real problems.

Getting collections you don’t have

pip install ansible already gave you the big bundle. When a playbook needs a collection outside it (or you’re on bare ansible-core), you install it by namespace and name:

ansible-galaxy collection install community.general
ansible-galaxy fetches collections, like a package manager

Lesson 26 covers pinning these in requirements.yml so every machine — and the CI runner — gets identical versions. For now, one habit is enough: when you see a module in the wild, read its namespace first. It tells you who maintains it and what you need installed before anything runs.

at work, this sounds like

“Use the FQCN or lint will fail the PR.”
Write ansible.builtin.copy, not copy — the CI linter enforces full module paths.
“Is that module in ansible.windows or community.windows?”
Which collection ships it — you may need to install a different one to use it.

self-check — recall, not a test

  1. 1 What are the three parts of an FQCN, in order?

  2. 2 A tutorial writes “- copy:” with no dots. Roughly when was it written, and why does it still run?

  3. 3 Why does ansible-lint care?

lab (optional — never required)

Run one ad-hoc ping twice — once as “ping”, once as “ansible.builtin.ping” — and confirm they resolve to the same module with ansible-doc.

needs: Any control node from lesson 5 (a Linux VM or container with ansible installed).

PLAY RECAP ************************** 04-collections-and-fqcn : ok=1 next=05-installing-the-control-node read=7m