class

Krikri::SynchronizeActionPlugin

Inherits Krikri::PluginHelpers::StrictBoolValidation < Krikri::ActionPlugin < Reference < Object

ansible.posix.synchronize as a controller-side action plugin that computes the ENTIRE task result itself (ActionResult.final - no module binary is ever dispatched, local or remote).

This mirrors Ansible's own architecture rather than working around this engine's: synchronize is not a normal target-side module there either. Its action plugin munges src/dest into rsync's remote form and hands off to a module that ultimately shells out to the rsync CLI - and it does so from the CONTROLLER (or the delegate_to host), with rsync making its OWN connection out to the remote end. Dispatched here the normal way (upload a plugin binary, run it ON the target), the rsync invocation would run on the wrong machine entirely: push mode's src: lives on the controller, which the target host has no path to. The rsync-arg-building/execution core itself lives in SynchronizeRsync (plugin_helpers/synchronize_rsync.cr), shared with plugins/synchronize.cr - the standalone binary kept for --async/ manual invocation, same split as debug/pause.

Supported and faithful: push (default; controller src -> remote dest) and pull (remote src -> controller dest) over the play's own SSH connection details (host/user/port, ansible_ssh_private_key_file, dest_port: override); both-ends-local sync (ansible_connection=local or delegate_to: localhost on a localhost task); delegate_to: localhost (any local-transport delegate) on a NON-localhost task host - Ansible then runs rsync on the controller with the TASK host as rsync's own ssh remote (target:/path, no connection plugin in between, verified live: a local-connection task host still gets qualified by its inventory name and rsync dials it over its own rsh); the full flag set (archive and its toggles, checksum, compress, delete, dirs, existing_only, recursive, links, copy_links, perms, times, owner, group, rsync_opts, rsync_path, rsync_timeout, partial, verify_host, private_key, link_dest, delay_updates, set_remote_user); role-relative src: dwim (handled executor-side in resolve_role_relative_src, before this runs). Idempotency comes from rsync itself - see SynchronizeRsync's changed-detection comment.

Known divergence: delegate_to: to a host that is neither localhost nor the sync endpoint (Ansible runs rsync ON the delegate, connecting out to the inventory host) is not modeled - here the delegate-resolved host IS the endpoint, which covers the shapes real roles actually write apart from that one: no delegate_to:, delegate_to: localhost, and delegate_to: the task's own host.

Constants

FAILURE_KEY_ORDER = ["rc", "cmd", "failed", "msg", "changed"]

Real failure shape: fail_json(msg=err, rc=rc, cmd=cmdstr) - fail_json's kwargs dict leads (rc, cmd), then failed/msg, and the controller appends changed then exception: registered as [rc, cmd, failed, msg, changed, exception] (exception backfilled at register via the _ansible_key_order marker - see TaskExecutor#apply_failed_key_order).

PARAM_FAILURE_KEY_ORDER = ["failed", "msg", "changed"]

Ansible module fail_json(msg="...") with no other kwargs: failed/msg lead (fail_json's dict(failed=True, msg=msg) update), then the controller's changed/exception backfill.

SUCCESS_KEY_ORDER = ["changed", "msg", "rc", "cmd", "stdout_lines", "failed"]

Ansible module success shape: exit_json(changed=, msg=, rc=, cmd=, stdout_lines=) then the controller backfills failed: false last. The empty msg is kept (the Ansible module passes msg=out_clean explicitly, and exit_json emits the key even as "").

Instance methods

execute

Execute action on controller Returns: modified params to send to remote plugin, or nil if action failed

Source