Ansible 2.8 Porting Guide

This section discusses the behavioral changes between Ansible 2.7 and Ansible 2.8.

It is intended to assist in updating your playbooks, plugins and other parts of your Ansible infrastructure so they will work with this version of Ansible.

We suggest you read this page along with Ansible Changelog for 2.8 to understand what updates you may need to make.

This document is part of a collection on porting. The complete list of porting guides can be found at porting guides.


Distribution Facts

The information returned for the ansible_distribution_* group of facts may have changed slightly. Ansible 2.8 uses a new backend library for information about distributions: nir0s/distro. This library runs on Python-3.8 and fixes many bugs, including correcting release and version names.

The two facts used in playbooks most often, ansible_distribution and ansible_distribution_major_version, should not change. If you discover a change in these facts, please file a bug so we can address the difference. However, other facts like ansible_distribution_release and ansible_distribution_version may change as erroneous information gets corrected.

Command Line

Become Prompting

Beginning in version 2.8, by default Ansible will use the word BECOME to prompt you for a password for elevated privileges (sudo privileges on unix systems or enable mode on network devices):

By default in Ansible 2.8:

ansible-playbook --become --ask-become-pass site.yml
BECOME password:

If you want the prompt to display the specific become_method you’re using, instead of the agnostic value BECOME, set AGNOSTIC_BECOME_PROMPT to False in your Ansible configuration.

By default in Ansible 2.7, or with AGNOSTIC_BECOME_PROMPT=False in Ansible 2.8:

ansible-playbook --become --ask-become-pass site.yml
SUDO password:


  • Setting the async directory using ANSIBLE_ASYNC_DIR as an task/play environment key is deprecated and will be removed in Ansible 2.12. You can achieve the same result by setting ansible_async_dir as a variable like:

    - name: run task with custom async directory
      command: sleep 5
      async: 10
        ansible_aync_dir: /tmp/.ansible_async
  • Plugin writers who need a FactCache object should be aware of two deprecations:

    1. The FactCache class has moved from ansible.plugins.cache.FactCache to ansible.vars.fact_cache.FactCache. This is because the FactCache is not part of the cache plugin API and cache plugin authors should not be subclassing it. FactCache is still available from its old location but will issue a deprecation warning when used from there. The old location will be removed in Ansible 2.12.
    2. The FactCache.update() method has been converted to follow the dict API. It now takes a dictionary as its sole argument and updates itself with the dictionary’s items. The previous API where update() took a key and a value will now issue a deprecation warning and will be removed in 2.12. If you need the old behaviour switch to FactCache.first_order_merge() instead.


Major changes in popular modules are detailed here

The exec wrapper that runs PowerShell modules has been changed to set $ErrorActionPreference = "Stop" globally. This may mean that custom modules can fail if they implicitly relied on this behaviour. To get the old behaviour back, add $ErrorActionPreference = "Continue" to the top of the module. This change was made to restore the old behaviour of the EAP that was accidentally removed in a previous release and ensure that modules are more resiliant to errors that may occur in execution.

Modules removed

The following modules no longer exist:

  • ec2_remote_facts
  • azure
  • cs_nic
  • netscaler
  • win_msi

Deprecation notices

The following modules will be removed in Ansible 2.12. Please update your playbooks accordingly.

Noteworthy module changes

  • The foreman and katello modules have been deprecated in favor of a set of modules that are broken out per entity with better idempotency in mind.
  • The foreman and katello modules replacement is officially part of the Foreman Community and supported there.
  • The tower_credential module originally required the ssh_key_data to be the path to a ssh_key_file. In order to work like Tower/AWX, ssh_key_data now contains the content of the file. The previous behavior can be achieved with lookup('file', '/path/to/file').
  • The win_scheduled_task module deprecated support for specifying a trigger repetition as a list and this format will be removed in Ansible 2.12. Instead specify the repetition as a dictionary value.
  • The win_feature module has removed the deprecated restart_needed return value, use the standardised reboot_required value instead.
  • The win_package module has removed the deprecated restart_required and exit_code return value, use the standardised reboot_required and rc value instead.
  • The win_get_url module has removed the deprecated win_get_url return dictionary, contained values are returned directly.
  • The win_get_url module has removed the deprecated skip_certificate_validation option, use the standardised validate_certs option instead.
  • The vmware_local_role_facts module now returns a list of dicts instead of a dict of dicts for role information.
  • If docker_network or docker_volume were called with diff: yes, check_mode: yes or debug: yes, a return value called diff was returned of type list. To enable proper diff output, this was changed to type dict; the original list is returned as diff.differences.
  • The na_ontap_cluster_peer module has replaced source_intercluster_lif and dest_intercluster_lif string options with source_intercluster_lifs and dest_intercluster_lifs list options
  • The modprobe module now detects kernel builtins. Previously, attempting to remove (with state: absent) a builtin kernel module succeeded without any error message because modprobe did not detect the module as present. Now, modprobe will fail if a kernel module is builtin and state: absent (with an error message from the modprobe binary like modprobe: ERROR: Module nfs is builtin.), and it will succeed without reporting changed if state: present. Any playbooks that are using changed_when: no to mask this quirk can safely remove that workaround. To get the previous behavior when applying state: absent to a builtin kernel module, use failed_when: false or ignore_errors: true in your playbook.


  • The powershell shell plugin now uses async_dir to define the async path for the results file and the default has changed to %USERPROFILE%\.ansible_async. To control this path now, either set the ansible_async_dir variable or the async_dir value in the powershell section of the config ini.

  • Order of enabled inventory plugins (INVENTORY_ENABLED) has been updated, auto is now before yaml and ini.

  • The private _options attribute has been removed from the CallbackBase class of callback plugins. If you have a third-party callback plugin which needs to access the command line arguments, use code like the following instead of trying to use self._options:

    from ansible import context
    tags = context.CLIARGS['tags']

    context.CLIARGS is a read-only dictionary so normal dictionary retrieval methods like CLIARGS.get('tags') and CLIARGS['tags'] work as expected but you won’t be able to modify the cli arguments at all.

Porting custom scripts

Display class

As of Ansible 2.8, the Display class is now a “singleton”. Instead of using __main__.display each file should import and instantiate ansible.utils.display.Display on its own.

OLD In Ansible 2.7 (and earlier) the following was used to access the display object:

    from __main__ import display
except ImportError:
    from ansible.utils.display import Display
    display = Display()

NEW In Ansible 2.8 the following should be used:

from ansible.utils.display import Display
display = Display()


No notable changes.