Ansible Custom Action Plugin Authoring Prompt
Draft a custom action plugin that runs controller-side logic and dispatches to a module safely, with check-mode support and no secret leakage.
- Target user
- Engineers who need controller-side processing (templating, file transfer, pre-checks) that a plain module can't do
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are a senior Ansible engineer who knows the difference between a module and an action plugin: modules run on the target, action plugins run on the controller and decide what (if anything) to ship to the target. You reach for an action plugin only when you genuinely need controller-side work — templating, file staging, argument preprocessing — and you keep it thin. I will describe behavior that needs controller-side logic. Draft an action plugin (`ActionBase` subclass) that implements it correctly. Steps: 1. **Justify the plugin**: confirm this actually needs to run on the controller; if a plain module would do, say so and stop. 2. **run() implementation**: implement `run(self, tmp, task_vars)`, call `super().run()`, do the controller-side work, then dispatch to the underlying module via `self._execute_module(...)` and merge results. 3. **Check mode**: honor `self._task.check_mode` — make the plugin report what it would do without making changes, and set `changed` honestly. 4. **Argument handling**: validate and normalize `self._task.args` before dispatch; never trust them blindly. 5. **File transfer**: if you stage files, use the provided connection/transfer helpers rather than shelling out, and clean up temp files. 6. **Secret hygiene**: ensure any sensitive args are not written to logs or returned in the result, and respect `no_log` on the task. Fill in: - Behavior needed and why it must be controller-side: [DESCRIBE] - Underlying module to dispatch to (if any): [e.g. copy, template, custom] - Args the plugin accepts: [LIST] - Any sensitive args: [LIST OR "none"] Output format: the action plugin Python with a docstring explaining the controller-side rationale, a sample task using it, a check-mode behavior note, and a test plan that runs it with `--check` first on a throwaway host. Do not run against real hosts first. Action plugins run with the controller's privileges and can read controller-side files and secrets; test on a scratch host with `--check` and inspect the result for leaked sensitive values before any real use.
Why this prompt works
Action plugins are the most misunderstood extension point in Ansible because they blur the controller/target boundary that keeps the rest of the system predictable. A module runs on the target and only sees what you send it; an action plugin runs on the controller, with the controller’s file access and secrets, and decides what to ship across the connection at all. That power is exactly why the first step of this prompt is a gate: confirm the behavior genuinely needs controller-side logic, and if a plain module would do, stop. Most “I need an action plugin” problems are really module problems, and writing the plugin anyway just adds controller-side risk.
When an action plugin is the right tool, the run() contract has sharp edges the prompt makes explicit. Calling super().run(), doing the controller-side work, then dispatching to the underlying module via self._execute_module and merging results is the pattern that keeps the plugin composable with the rest of Ansible. Honoring check_mode is non-negotiable: an action plugin that makes changes under --check silently breaks every dry run that touches it, which undermines the one safety mechanism operators rely on most.
The secret-hygiene focus reflects where action plugins actually leak. Because they run on the controller, they can read controller-side files and credentials, and a sloppy implementation returns those in the task result or writes them to logs. The prompt keeps sensitive args out of logs and results, respects no_log, and insists the first run happen on a scratch host with --check and a leaked-value inspection — so a powerful, controller-privileged plugin stays under human review before it ever touches production.