ansible/ansible
Plugin loader
The plugin loader resolves plugin names to Python classes across multiple search paths: built-in (lib/ansible/plugins/<type>/), installed collections (~/.ansible/collections/, /usr/share/ansible/collections/), and user-configured directories. There is one PluginLoader instance per plugin type.
The collection loader sits underneath: it's a Python MetaPathFinder so import ansible_collections.<ns>.<col>... Just Works for installed collections.
Files
| File | Lines | Purpose |
|---|---|---|
lib/ansible/plugins/loader.py |
1,905 | PluginLoader class, instances per type, plugin name resolution |
lib/ansible/plugins/__init__.py |
8042 | AnsibleJinja2Plugin, AnsiblePlugin base; module/path caches |
lib/ansible/plugins/list.py |
11410 | Plugin enumeration helpers (used by ansible-doc -l) |
lib/ansible/utils/collection_loader/__init__.py |
(re-exports) | Public API of the collection loader |
lib/ansible/utils/collection_loader/_collection_finder.py |
(large) | The MetaPathFinder implementation |
lib/ansible/utils/collection_loader/_collection_config.py |
(small) | Mutable config (search paths, default collection) |
lib/ansible/config/ansible_builtin_runtime.yml |
(data) | The legacy short-name → FQCN redirect map |
Plugin types
ansible-core knows about 17 plugin types, each backed by a PluginLoader instance at module top-level in loader.py:
| Type | Loader var | Search dir | What it does |
|---|---|---|---|
| Action | action_loader |
lib/ansible/plugins/action/ |
Controller-side half of a module call |
| Become | become_loader |
lib/ansible/plugins/become/ |
Privilege escalation: sudo/su/runas |
| Cache | cache_loader |
lib/ansible/plugins/cache/ |
Fact cache backends |
| Callback | callback_loader |
lib/ansible/plugins/callback/ |
Event consumers (display, junit, tree, ...) |
| Cliconf | cliconf_loader |
lib/ansible/plugins/cliconf/ |
CLI handshake for network platforms |
| Connection | connection_loader |
lib/ansible/plugins/connection/ |
Talks to a remote target |
| Doc fragments | fragment_loader |
lib/ansible/plugins/doc_fragments/ |
Reusable YAML fragments for module docs |
| Filter | filter_loader |
lib/ansible/plugins/filter/ |
Jinja {{ x | filter }} |
| HttpAPI | httpapi_loader |
lib/ansible/plugins/httpapi/ |
REST handshake for network platforms |
| Inventory | inventory_loader |
lib/ansible/plugins/inventory/ |
Resolve inventory sources to hosts/groups |
| Lookup | lookup_loader |
lib/ansible/plugins/lookup/ |
{{ lookup('name', ...) }} |
| Module | module_loader |
lib/ansible/modules/ |
The remote-side modules themselves |
| Module utils | module_utils_loader |
lib/ansible/module_utils/ |
Module support code |
| Netconf | netconf_loader |
lib/ansible/plugins/netconf/ |
NETCONF protocol for network devices |
| Shell | shell_loader |
lib/ansible/plugins/shell/ |
Remote shell command quoting (sh, csh, fish, powershell) |
| Strategy | strategy_loader |
lib/ansible/plugins/strategy/ |
Task scheduling |
| Terminal | terminal_loader |
lib/ansible/plugins/terminal/ |
Network device terminal handlers |
| Test | test_loader |
lib/ansible/plugins/test/ |
Jinja {{ x is testname }} |
| Vars | vars_loader |
lib/ansible/plugins/vars/ |
Var sources (host_group_vars and similar) |
There is no cliconf, httpapi, netconf, or terminal plugin shipped in ansible-core — these types exist for collections to populate.
Resolving a plugin name
graph TD
REQ[get plugin: 'foo' or 'ns.col.foo'] --> ISSPEC{Has dots?}
ISSPEC -->|no, e.g. 'foo'| LEGACY[Treat as 'ansible.legacy.foo']
ISSPEC -->|yes, FQCN| FQCN[Treat as namespace.collection.name]
LEGACY --> RTM[Check ansible_builtin_runtime.yml redirect]
RTM -->|redirected to FQCN| FQCN
RTM -->|no redirect| BUILTIN[Look in lib/ansible/plugins/<type>/]
FQCN --> COLLECTION[Look in collection's plugins/<type>/]
BUILTIN -->|found| LOAD[Import + instantiate]
COLLECTION -->|found| LOAD
BUILTIN -->|miss| NOT_FOUND[AnsibleError: plugin not found]
COLLECTION -->|miss| NOT_FOUNDConcretely, PluginLoader.get('copy') does the following:
- Normalize: a bare name like
copybecomesansible.legacy.copy. - Consult
lib/ansible/config/ansible_builtin_runtime.yml. The redirect map covers the entire pre-2.10 module/plugin namespace.ec2redirects toamazon.aws.ec2;mysql_userredirects tocommunity.mysql.mysql_user; manyansible.legacy.*names redirect toansible.builtin.*. - For an FQCN: ask the collection loader to find the file. The collection loader enumerates the configured collection paths (
COLLECTIONS_PATHSconfig), looks for<root>/ansible_collections/<ns>/<col>/plugins/<type>/<name>.py(or.ymlfor filter/test/lookup pure-data plugins), and imports it. - For
ansible.builtin.*(after legacy redirect): look inlib/ansible/plugins/<type>/. - Cache the resolved class in
PLUGIN_PATH_CACHE(inlib/ansible/plugins/__init__.py) for subsequent calls.
The PluginLoadContext returned by the loader carries the resolved class plus metadata: the original name, the redirect chain, deprecation warnings to emit, and the resolved FQCN.
The collection loader
lib/ansible/utils/collection_loader/_collection_finder.py defines _AnsibleCollectionFinder, a sys.meta_path entry that intercepts imports of ansible_collections.<ns>.<col>.... It maps each segment to a directory on disk — there's no compiled metadata, just filesystem walking and importlib machinery underneath.
This means a collection plugin can do ordinary Python imports inside itself:
from ansible_collections.community.general.plugins.module_utils.helper import some_helperThe finder also handles role redirects, plugin redirects (per-collection meta/runtime.yml files), and synthetic packages like ansible.builtin and ansible.legacy that map to ansible-core's own files.
AnsibleCollectionConfig (lib/ansible/utils/collection_loader/_collection_config.py) holds runtime-mutable collection state: search paths, the "default collection" set by play-level collections: keywords, and a few flags.
Caching
Three caches in lib/ansible/plugins/__init__.py:
MODULE_CACHE— keyed by full path, holds imported module objects.PATH_CACHE— keyed by(plugin_type, name), holds resolved file paths.PLUGIN_PATH_CACHE— keyed by(plugin_type, name, search_path), finer grained.
Caches are populated lazily and invalidated only on full process restart. The fork-and-exec model of workers means each fork inherits the parent's caches, so caching is effective across the run.
Deprecations and circular redirects
The loader detects two kinds of error scenarios:
AnsiblePluginRemovedError— a name in the redirect map saysremoved:rather thanredirect:. The user gets a useful message pointing to the replacement.AnsiblePluginCircularRedirect—fooredirects tobar, which redirects back tofoo. Detected by tracking the redirect chain.
Each redirect step also carries an optional deprecation: block; the loader emits display.deprecated warnings as it follows the chain.
Integration points
- Imports from:
ansible.utils.collection_loader,ansible.parsing.yaml.loader(to read collectionmeta/runtime.yml),ansible.utils.display(for warnings). - Imported by: every CLI (early init),
lib/ansible/executor/task_executor.py,lib/ansible/executor/task_queue_manager.py, every action/strategy/callback plugin that wants to call out to a peer. - Backed by:
lib/ansible/config/ansible_builtin_runtime.ymlfor redirects andlib/ansible/utils/collection_loader/for collection lookup.
Entry points for modification
- Adding a new plugin type is rare and disruptive. It requires a new loader instance, a base class under
lib/ansible/plugins/, sanity-test updates, and probably avalidate-modulesanalog. Don't do it lightly. - Adding redirects for compatibility goes in
lib/ansible/config/ansible_builtin_runtime.yml. Sanity testruntime-metadatavalidates the file's shape. - Debugging plugin resolution — set
ANSIBLE_DEBUG=1and run with-vvv; the loader emits its search path attempts.
Cross-links
- Plugins — the per-type plugin guides.
- Features → Collections — what gets installed and where the loader looks.
- Reference → Configuration —
COLLECTIONS_PATHS,DEFAULT_LOAD_CALLBACK_PLUGINS, etc.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.