Mitigating deprecation of --one-line and associated callback plugin

With the deprecation of the --one-line parameter and its associated callback plugin, I’m working on simplifying the use of a suggested workaround. First, a little background.

  • Everything “interesting” in Ansible is implemented as a plugin.
  • Callback plugins control the presentation of the console output from various Ansible commands, particularly ansible and ansible-playbook.
  • The oneline callback puts each task’s output for each target host on a single line (so one line per host per task). For some cases, especially ad hoc commands with short task output from many hosts, this can often be much simpler for humans to read.
  • The oneline.py callback plugin is deprecated and will be removed from ansible-core version 2.23, at the same time the -o /--one-line parameters will be removed from core commands.
  • The suggestion, for those who find --one-line occasionally useful, is to use a private copy of the oneline.py callback plugin, with the caveat that you’ll own any maintenance issues going forward.

That’s great, but using a one-off callback requires changing some config, either in ansible.cfg or environment variables. The ideal would be something nearly as simple as adding --one-line to your ad hoc command parameters. That’s possible, but it requires a bit of one-time setup.

First, you’ll need to create a place for your private copy of the oneline.py callback plugin. This should be in your DEFAULT_CALLBACK_PLUGIN_PATH; see ansible-config list to be sure.

$ mkdir -p ~/.ansible/plugins/callback

Next, copy Ansible’s current oneline.py callback plugin to the private plugins/callback directory you just created. Give it a slightly different name — here I’m using “xoneline.py” — to avoid plugin name collisions before the final removal from ansible-core 2.23.

$ cp "$(ansible --version | grep -Po '(?<=ansible python module location = ).*')"/plugins/callback/oneline.py ~/.ansible/plugins/callback/xoneline.py

Then edit ~/.ansible/plugins/callback/xoneline.py to comment out the lines pertaining to the pending deprecation of the oneline plugin. Don’t be shy about editing that file. You own it now. In ansible-core 2.20, that will look something like this:

        # self._display.deprecated(  # pylint: disable=ansible-deprecated-unnecessary-collection-name
        #     msg='The xoneline callback plugin is deprecated.',
        #     version='2.23',
        #     deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,  # entire plugin being removed; this improves the messaging
        # )

Finally, create an alias that sets a few environment variables as a prefix to your ad hoc ansible commands. You’ll want to update your “dotfiles”, wherever you set your personal shell aliases, to have it defined on subsequent shell sessions.
N.B. - The trailing space on this alias is important!

$ alias xoneline='ANSIBLE_CALLBACKS_ENABLED=xoneline ANSIBLE_LOAD_CALLBACK_PLUGINS=true ANSIBLE_STDOUT_CALLBACK=xoneline '

Notice this alias doesn’t execute any commands. You invoke the alias as a prefix to your ad hoc ansible commands, so that these two ad hoc commands are essentially equivalent (with spaces inserted to facilitate comparison):

$          ansible my_hosts -a 'uname -r' --one-line
$ xoneline ansible my_hosts -a 'uname -r'

Only the latter one (may) work with ansible-core 2.23 and beyond.

The trailing space on that alias causes the word after the alias to also be subject to alias expansion. (See help alias in bash.) This can be useful if you, like me, have other aliases for specific ansible invocations. For example, I have this alias:

alias ansible-md='ansible -i /path/to/myinventory/hosts -u ansible-mydomain --ssh-extra-args="-i=/path/to/id_rsa_ansible_mydomain"'

so that

$ xoneline ansible-md …

expands to a lot more than I want to type. Without the trailing space in the xoneline alias definition, my ansible-md alias would not expand in that command.

2 Likes

I never used oneliner functionality, but recently I’ve been thinking that there should be callback plugin that “swallows” almost all the playbook output for the sake of not polluting LLM context. When you want LLM to analyze issue in the role or playbook, it might be beneficial to keep only failed tasks (and maybe some context around them).

That is why oneline callback (or other callback that will hide not important parts) seems like a good idea for LLMs. Thank you for sharing

In few of my projects I’ve adopted following technique - when any CI action is executed with env var LLM=1 almost all output skipped, only failures are shown. I think something similar can be adopted here - run all the playbooks with oneline callback allways on, but it will change anything only if env var is set.

I created a thread about keeping that plugin in a collection (instead of everyone having their own fork): Add oneline callback to a collection (like community.general)?