Join AnsibleFest at Red Hat Summit!

Ansible 12 Porting Guide

Ansible 12 is based on Ansible-core 2.19.

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

Introduction

This release includes an overhaul of the templating system and a new feature dubbed Data Tagging. These changes enable reporting of numerous problematic behaviors that went undetected in previous releases, with wide-ranging positive effects on security, performance, and user experience.

Backward compatibility has been preserved where practical, but some breaking changes were necessary. This guide describes some common problem scenarios with example content, error messsages, and suggested solutions.

Playbook

Broken Conditionals

Broken conditionals occur when the input expression or template is not a string, or the result is not a boolean. Python and Jinja provide implicit “truthy” evaluation of most non-empty non-boolean values in conditional expressions. While sometimes desirable for brevity, truthy conditional evaluation often masks serious logic errors in playbooks that could not be reliably detected by previous versions of ansible-core.

Changes to templating in this release detects non-boolean conditionals during expression evaluation and reports an error by default. The error can be temporarily reduced to a warning with the ALLOW_BROKEN_CONDITIONALS config setting.

The following examples are derived from broken conditionals that masked logic errors in actual playbooks.

Example - implicit boolean conversion

This expression relies on an implicit truthy evaluation of inventory_hostname. An explicit predicate with a boolean result, such as | length > 0 or is truthy, should be used instead.

- assert:
    that: inventory_hostname

The error reported is:

Conditional result was 'localhost' of type 'str', which evaluates to True. Conditionals must have a boolean result.

This can be resolved by using an explicit boolean conversion:

- assert:
    that: inventory_hostname | length > 0

Example - unintentional truthy conditional

The second part of this conditional is erroneously quoted. The quoted part becomes the expression result (evaluated as truthy), so the expression can never be False.

- assert:
    that: inventory_hostname is defined and 'inventory_hostname | length > 0'

The error reported is:

Conditional result was 'inventory_hostname | length > 0' of type 'str', which evaluates to True. Conditionals must have a boolean result.

This can be resolved by removing the erroneous quotes:

- assert:
    that: inventory_hostname is defined and inventory_hostname | length > 0

Example - expression syntax error

Previous Ansible releases could mask some expression syntax errors as a truthy result.

- assert:
    that: 1 == 2,
#               ^ invalid comma

The error reported is:

Syntax error in expression: chunk after expression

This can be resolved by removing the invalid comma after the expression.

Example - Jinja order of operations

This expression uses the ~ concatenation operator, which is evaluated after the contains test. The result is always a non-empty string, which is truthy.

- assert:
    that: inventory_hostname is contains "local" ~ "host"

The error reported is:

Conditional result was 'Truehost' of type 'str', which evaluates to True. Conditionals must have a boolean result.

This can be resolved by inserting parentheses to resolve the concatenation operation before the contains test:

- assert:
    that: inventory_hostname is contains("local" ~ "host")

Example - dictionary as conditional

This conditional should have been quoted. In a YAML list element, an unquoted string with a space after a colon is interpreted by the YAML parser as a mapping. Non-empty mappings are always truthy.

- assert:
    that:
     - result.msg == "some_key: some_value"
#                             ^^ colon+space == problem

The error reported is:

Conditional expressions must be strings.

This can be resolved by quoting the entire assertion expression:

- assert:
    that:
     - 'result.msg == "some_key: some_value"'

Multi-pass templating

Embedding templates within other templates or expressions could previously result in untrusted templates being executed. The overhauled templating engine in this release no longer supports this insecure behavior.

Example - unnecessary template in expression

This conditional references a variable using a template instead of using the variable directly in the expression.

- assert:
    that: 1 + {{ value }} == 2
  vars:
    value: 1

The error reported is:

Syntax error in expression. Template delimiters are not supported in expressions: expected token ':', got '}'

This can be resolved by referencing the variable without a template:

- assert:
    that: 1 + value == 2
  vars:
    value: 1

Example - dynamic expression construction

This conditional is dynamically created using a template, which is expected to be evaluated as an expression. Previously, the template was rendered by task argument templating, resulting in a plain string, which was later evaluated by the assert action.

- assert:
    that: inventory_hostname {{ comparison }} 'localhost'
  vars:
    comparison: ==

The error reported is:

Syntax error in expression. Template delimiters are not supported in expressions: chunk after expression

Dynamic expression construction from playbooks is insecure and unsupported.

Troubleshooting untrusted templates

By default, untrusted templates are silently ignored. Troubleshooting trust issues with templates can be aided by enabling warnings or errors for untrusted templates. The environment variable _ANSIBLE_TEMPLAR_UNTRUSTED_TEMPLATE_BEHAVIOR can be used to control this behavior.

Valid options are:

  • warn - A warning will be issued when an untrusted template is encountered.

  • fail - An error will be raised when an untrusted template is encountered.

  • ignore - Untrusted templates are silently ignored and used as-is. This is the default behavior.

Note

This optional warning and failure behavior is experimental and subject to change in future versions.

Loops no longer leak omit placeholders

Omit placeholders no longer leak between loop item templating and task templating.

Previously, omit placeholders could remain embedded in loop items after templating and be used as an omit for task templating. Now, values resolving to omit are dropped immediately when loop items are templated.

To turn missing values into an omit for task templating, use | default(omit). This solution is backward compatible with previous versions of ansible-core.

Example - missing default(omit)

The following task tries to pass omit from a loop to the task, but the value is undefined since it was omitted:

- debug:
    msg: "{{ item.msg }}"  # 'msg' is undefined
  loop:
   - msg: "{{ omit }}"  # 'msg' will be omitted from the loop item

This updated task uses default(omit) on the missing value to ensure it is omitted for the task:

- debug:
    msg: "{{ item.msg | default(omit) }}"  # 'msg' is undefined, use 'default(omit)' to turn it into an omit
  loop:
   - msg: "{{ omit }}"  # passed through in earlier versions, this value is now omitted from the loop item

Privilege escalation timeouts

Timeout waiting on privilege escalation (become) is now an unreachable error instead of a task error. Existing playbooks should be changed to replace ignore_errors with ignore_unreachable on tasks where timeout on become should be ignored.

Engine

Templating

Template trust model inversion

Previously, ansible-core implicitly trusted all string values to be rendered as Jinja templates, but applied an “unsafe” wrapper object around strings obtained from untrusted sources (for example, module results). Unsafe-wrapped strings were silently ignored by the template engine, as many templating operations can execute arbitrary code on the control host as the user running ansible-core. This required any code that operated on strings to correctly propagate the wrapper object, which resulted in numerous CVE-worthy RCE (remote code execution) vulnerabilities.

This release inverts the previous trust model. Only strings marked as loaded from a trusted source are eligible to be rendered as templates. Untrusted values can (as before) be referenced by templates, but the template expression itself must always be trusted. While this change still requires consideration for propagation of trust markers when manipulating strings, failure to do so now results in a loss of templating ability instead of a potentially high-severity security issue.

Attempts to render a template appearing in an untrusted string will (as before) return the original string unmodified. By default, attempting to render an untrusted template fails silently, though such failures can be elevated to a warning or error via configuration.

Newly-created string results from template operations will never have trust automatically applied, though templates that return existing trusted string values unmodified will not strip their trust. It is also possible for plugins to explicitly apply trust.

Backward-compatible template trust behavior is applied automatically in most cases; for example, templates appearing in playbooks, roles, variable files, and most built-in inventory plugins will yield trusted template strings. Custom plugins that source template strings will be required to use new public APIs to apply trust where appropriate.

See Plugin API and Troubleshooting untrusted templates for additional information.

Native Jinja mode required

Previous versions supported templating in two different modes:

  • Jinja’s original string templating mode converted the result of each templating operation to a string.

  • Jinja’s native mode usually preserved variable types in template results.

In both modes, ansible-core evaluated the final template string results as Python literals, falling back to the original string if the evaluation resulted in an error. Selection of the templating mode was controlled by configuration, defaulting to Jinja’s original string templating.

Jinja’s native templating mode is now used exclusively. The configuration option for setting the templating mode is deprecated and no longer has any effect.

Preservation of native types in templating has been improved to correct gaps in the previous implementation, entirely eliminating the final literal evaluation pass (a frequent source of confusion, errors, and performance issues). In rare cases where playbooks relied on implicit object conversion from strings, an explicit conversion will be required.

Some existing templates may unintentionally convert non-strings to strings. In previous versions this conversion could be masked by the evaluation of strings as Python literals.

Example - unintentional string conversion

This expression erroneously passes a list to the replace filter, which operates only on strings. The filter silently converts the list input to a string. Due to some string results previously parsing as lists, this mistake often went undetected in earlier versions.

- debug:
    msg: "{{ ['test1', 'test2'] | replace('test', 'prod') }}"

The result of this template becomes a string:

ok: [localhost] => {
    "msg": "['prod1', 'prod2']"
}

This can be resolved by using the map filter to apply the replace filter to each list element:

- debug:
    msg: "{{ ['test1', 'test2'] | map('replace', 'test', 'prod') }}"

The result of the corrected template remains a list:

ok: [localhost] => {
    "msg": [
        "prod1",
        "prod2"
    ]
}

Lazy templating

Ansible’s interface with the Jinja templating engine has been heavily refined, yielding significant performance improvements for many complex templating operations. Previously, deeply-nested, recursive, or self-referential templating operations were always resolved to their full depth and breadth on every access, including repeated access to the same data within a single templating operation. This resulted in expensive and repetitive evaluation of the same templates within a single logical template operation, even for templates deep inside nested data structures that were never directly accessed. The new template engine lazily defers nearly all recursion and templating until values are accessed, or known to be exiting the template engine, and intermediate nested or indirected templated results are cached for the duration of the template operation, reducing repetitive templating. These changes have shown exponential performance improvements for many real-world complex templating scenarios.

Error handling

Contextual warnings and errors

Changes to internal error handling in ansible-core will be visible in many situations that result in a warning or error. In most cases, the operational context (what was happening when the error or warning was generated) and data element(s) involved are captured and included in user-facing messages. Errors and warnings that occur during task execution are more consistently included in the task result, with the full details accessible to callbacks and (in the case of errors), a minimal error message in the msg field of the result. Due to the standardized nature of this error handling, seemingly redundant elements may appear in some error messages. These will improve over time as other error handling improvements are made but are currently necessary to ensure proper context is available in all error situations. Error message contents are not considered stable, so automation that relies on them should be avoided when possible.

Variable provenance tracking

The new Data Tagging feature expands provenance tracking on variables to nearly every source. This allows for much more descriptive error messaging, as the entire chain of execution can be consulted to include contextual information about what was happening when an error occurred. In most cases, this includes file path, source lines, and column markers. Non-file variable sources such as CLI arguments, inventory plugins and environment are also supported.

Deprecation warnings on value access

New features allow most ansible-core variables and values to be tagged as deprecated. Plugins and modules can apply these tags to augment deprecated elements of their return values with a description and help text to suggest alternatives, which will be displayed in a runtime warning when the tagged value is accessed by, for example, a playbook or template. This allows for easier evolution and removal of module and fact results, and obsolete core behaviors.

For example, accessing the deprecated play_hosts magic variable will trigger a deprecation warning that suggests the use of the ansible_play_batch variable instead.

Improved Ansible module error handling

Ansible modules implemented in Python now have exception handling provided by the AnsiballZ wrapper. In previous versions of ansible-core, unhandled exceptions in an Ansible module simply printed a traceback and exited without providing a standard module response, which caused the task result to contain a generic MODULE FAILURE message and any raw output text produced by the module.

To address this, modules often implemented unnecessary try/except blocks around most code where specific error handling was not possible, only to call AnsibleModule.fail_json with a generic failure message. This pattern is no longer necessary, as all unhandled exceptions in Ansible Python modules are now captured by the AnsiballZ wrapper and returned as a structured module result, with automatic inclusion of traceback information when enabled by the controller.

Improved handling of undefined

Undefined handling has been improved to avoid situations where a Jinja plugin silently ignores undefined values.

This commonly occurs when a Jinja plugin, such as a filter or test, checks the type of a variable without accounting for the possibility of an undefined value being present.

Example - missing attribute

This task incorrectly references an undefined exists attribute from a stat result in a conditional. The undefined value was not detected in previous versions because it is passed to the false Jinja test plugin, which silently ignores undefined values. As a result, this conditional could never be True in earlier versions of ansible-core, and there was no indication that the failed_when expression was invalid.

- stat:
    path: /does-not-exist
  register: result
  failed_when: result.exists is false
  #                   ^ missing reference to stat

In the current release the faulty expression is detected and results in an error.

This can be corrected by adding the missing stat attribute to the conditional:

- stat:
    path: /does-not-exist
  register: result
  failed_when: result.stat.exists is false

Displaying tracebacks

In previous ansible-core versions, tracebacks from some controller-side errors were available by increasing verbosity with the -vvv option, but the availability and behavior was inconsistent. This feature was also limited to errors.

Handling of errors, warnings and deprecations throughout much of the ansible-core codebase has now been standardized. Tracebacks can be optionally collected and displayed for all exceptions, as well as at the call site of errors, warnings, or deprecations (even in module code) using the ANSIBLE_DISPLAY_TRACEBACK environment variable.

Valid options are:

  • always - Tracebacks will always be displayed. This option takes precedence over others below.

  • never - Tracebacks will never be displayed. This option takes precedence over others below.

  • error - Tracebacks will be displayed for errors.

  • warning - Tracebacks will be displayed for warnings other than deprecation warnings.

  • deprecated - Tracebacks will be displayed for deprecation warnings.

Multiple options can be combined by separating them with commas.

Plugin API

Deprecating values

Plugins and Python modules can tag returned values as deprecated with the new deprecate_value function from ansible.module_utils.datatag. A description of the deprecated feature, optional help text, and removal timeframes can be attached to the value, which will appear in a runtime warning if the deprecated value is referenced in an expression. The warning message will include information about the module/plugin that applied the deprecation tag and the location of the expression that accessed it.

from ansible.module_utils.datatag import deprecate_value

...

module.exit_json(
    color_name=deprecate_value(
        value="blue",
        msg="The `color_name` return value is deprecated.",
        help_text="Use `color_code` instead.",
    ),
    color_code="#0000ff",
)

When accessing the color_name from the module result, the following warning will be shown:

[DEPRECATION WARNING]: The `color_name` return value is deprecated. This feature will be removed from the 'ns.collection.paint' module in a future release.
Origin: /examples/use_deprecated.yml:8:14

6
7     - debug:
8         var: result.color_name
               ^ column 14

Use `color_code` instead.

Applying template trust to individual values

String values are no longer trusted to be rendered as templates by default. Strings loaded from playbooks, vars files, and other built-in trusted sources are usually marked trusted by default. Plugins that create new string instances with embedded templates must use the new trust_as_template function from ansible.template to tag those values as originating from a trusted source to allow the templates to be rendered.

Warning

This section and the associated public API are currently incomplete.

Applying template trust in inventory and vars plugins

Inventory plugins can set group and host variables. In most cases, these variables are static values from external sources and do not require trust. Values that can contain templates will require explicit trust via trust_as_template to be allowed to render, but trust should not be applied to variable values from external sources that could be maliciously altered to include templates.

Warning

This section and the associated public API are currently incomplete.

Raising exceptions

When raising exceptions in an exception handler, be sure to use raise ... from as appropriate. This supersedes the use of the AnsibleError arg orig_exc to represent the cause. Specifying orig_exc as the cause is still permitted for backward compatibility.

Failure to use raise ... from when orig_exc is set will result in a warning. Additionally, if the two cause exceptions do not match, a warning will be issued.

Overly-broad exception handling in Jinja plugins

Jinja plugins with overly broad exception handling, such as except Exception, may behave incorrectly when accessing the contents of variables which are containers (dict, list). This can occur when a templated value from a variable is undefined, is an undecryptable vaulted value, or another value which triggers lazily reported fault conditions.

Jinja plugins should catch more specific exception types where possible, and do so around the smallest reasonable portion of code. Be especially careful to avoid broad exception handling around code which accesses the contents of container variables.

Ansible custom data types

Many variable objects in ansible-core are represented by custom types. In previous versions these could be seen as types such as:

  • AnsibleUnicode (a subclass of str)

  • AnsibleSequence (a subclass of list)

  • AnsibleMapping (a subclass of dict)

These types, and more, now have new subclasses derived from their native Python types. In most cases these types behave indistinguishably from the types they extend, and existing code should function normally. However, some Python libraries do not handle builtin object subclasses properly. Custom plugins that interact with such libraries may require changes to convert and pass the native types.

Warning

This section and the associated public API are currently incomplete.

AnsibleVaultEncryptedUnicode replaced by EncryptedString

The AnsibleVaultEncryptedUnicode type has been replaced by EncryptedString.

Plugins which create AnsibleVaultEncryptedUnicode will now receive EncryptedString instances instead. This feature ensures backward compatibility with previous versions of ansible-core.

Plugins which perform isinstance checks, looking for AnsibleVaultEncryptedUnicode, will no longer encounter these types. Values formerly represented by that type will now appear as a tagged str instead. Special handling in plugins is no longer required to access the contents of these values.

Command Line

No notable changes

Deprecated

No notable changes

Modules

No notable changes

Modules removed

The following modules no longer exist:

  • No notable changes

Deprecation notices

No notable changes

Noteworthy module changes

No notable changes

Plugins

Noteworthy plugin changes

  • The ssh connection plugin now supports using SSH_ASKPASS to supply passwords for authentication as an alternative to the sshpass program. The default is to use SSH_ASKPASS instead of sshpass. This is controlled by the password_mechanism configuration for the ssh connection plugin. To switch back to using sshpass make one of the following changes:

    To your ansible.cfg file:

    [ssh_connection]
    password_mechanism = sshpass
    

    By exporting an environment variable:

    export ANSIBLE_SSH_PASSWORD_MECHANISM=sshpass
    

    By setting the following variable:

    ansible_ssh_password_mechanism: sshpass
    
  • Coercing unrecognized input values in the bool filter is deprecated. The bool filter now returns only True or False, depending on the input:

    • True - Returned for True, 1 and case-insensitive matches on the strings: “yes”, “on”, “true”, “1”

    • False - Returned for False, 0 and case-insensitive matches on the strings: “no”, “off”, “false”, “0”

    Any other input will result in a deprecation warning. This warning will become an error in ansible-core 2.23.

    When a deprecation warning is issued, the return value is False unless the input equals 1, which can occur when the input is the float value of 1.0.

    This filter now returns False instead of None when the input is None. The aforementioned deprecation warning is also issued in this case.

Porting custom scripts

No notable changes

Networking

No notable changes

Porting Guide for v12.0.0a2

Known Issues

Major Changes

Deprecated Features

Porting Guide for v12.0.0a1

Added Collections

  • hitachivantara.vspone_block (version 3.3.0)

  • microsoft.iis (version 1.0.2)

Known Issues

  • templating - Any string value starting with #jinja2: which is templated will always be interpreted as Jinja2 configuration overrides. To include this literal value at the start of a string, a space or other character must precede it.

  • variables - Tagged values cannot be used for dictionary keys in many circumstances.

  • variables - The values None, True and False cannot be tagged because they are singletons. Attempts to apply tags to these values will be silently ignored.

  • idrac_diagnostics - Issue(285322) - This module doesn’t support export of diagnostics file to HTTP and HTTPS share via SOCKS proxy.

  • idrac_firmware - Issue(279282) - This module does not support firmware update using HTTP, HTTPS, and FTP shares with authentication on iDRAC8.

  • ome_smart_fabric_uplink - Issue(186024) - The module supported by OpenManage Enterprise Modular, however it does not allow the creation of multiple uplinks of the same name. If an uplink is created using the same name as an existing uplink, then the existing uplink is modified.

  • All Fusion fleet members will be assumed to be at the same Purity//FA version level as the array connected to by Ansible.

  • FlashArray//CBS is not currently supported as a member of a Fusion fleet

Breaking Changes

  • Support for the toml library has been removed from TOML inventory parsing and dumping. Use tomli for parsing on Python 3.10. Python 3.11 and later have built-in support for parsing. Use tomli-w to support outputting inventory in TOML format.

  • assert - The quiet argument must be a commonly-accepted boolean value. Previously, unrecognized values were silently treated as False.

  • callback plugins - The structure of the exception, warnings and deprecations values visible to callbacks has changed. Callbacks that inspect or serialize these values may require special handling.

  • conditionals - Conditional expressions that result in non-boolean values are now an error by default. Such results often indicate unintentional use of templates where they are not supported, resulting in a conditional that is always true. When this option is enabled, conditional expressions which are a literal None or empty string will evaluate as true, for backwards compatibility. The error can be temporarily changed to a deprecation warning by enabling the ALLOW_BROKEN_CONDITIONALS config option.

  • first_found lookup - When specifying files or paths as a templated list containing undefined values, the undefined list elements will be discarded with a warning. Previously, the entire list would be discarded without any warning.

  • internals - The AnsibleLoader and AnsibleDumper classes for working with YAML are now factory functions and cannot be extended.

  • internals - The ansible.utils.native_jinja Python module has been removed.

  • inventory - Invalid variable names provided by inventories result in an inventory parse failure. This behavior is now consistent with other variable name usages throughout Ansible.

  • lookup plugins - Lookup plugins called as with_(lookup) will no longer have the _subdir attribute set.

  • lookup plugins - terms will always be passed to run as the first positional arg, where previously it was sometimes passed as a keyword arg when using with_ syntax.

  • loops - Omit placeholders no longer leak between loop item templating and task templating. Previously, omit placeholders could remain embedded in loop items after templating and be used as an omit for task templating. Now, values resolving to omit are dropped immediately when loop items are templated. To turn missing values into an omit for task templating, use | default(omit). This solution is backwards compatible with previous versions of ansible-core.

  • modules - Ansible modules using sys.excepthook must use a standard try/except instead.

  • plugins - Any plugin that sources or creates templates must properly tag them as trusted.

  • plugins - Custom Jinja plugins that accept undefined top-level arguments must opt in to receiving them.

  • plugins - Custom Jinja plugins that use environment.getitem to retrieve undefined values will now trigger a MarkerError exception. This exception must be handled to allow the plugin to return a Marker, or the plugin must opt-in to accepting Marker values.

  • public API - The ansible.vars.fact_cache.FactCache wrapper has been removed.

  • serialization of omit sentinel - Serialization of variables containing omit sentinels (e.g., by the to_json and to_yaml filters or ansible-inventory) will fail if the variable has not completed templating. Previously, serialization succeeded with placeholder strings emitted in the serialized output.

  • set_fact - The string values “yes”, “no”, “true” and “false” were previously converted (ignoring case) to boolean values when not using Jinja2 native mode. Since Jinja2 native mode is always used, this conversion no longer occurs. When boolean values are required, native boolean syntax should be used where variables are defined, such as in YAML. When native boolean syntax is not an option, the bool filter can be used to parse string values into booleans.

  • template lookup - The convert_data option is deprecated and no longer has any effect. Use the from_json filter on the lookup result instead.

  • templating - Access to _ prefixed attributes and methods, and methods with known side effects, is no longer permitted. In cases where a matching mapping key is present, the associated value will be returned instead of an error. This increases template environment isolation and ensures more consistent behavior between the . and [] operators.

  • templating - Conditionals and lookups which use embedded inline templates in Jinja string constants now display a warning. These templates should be converted to their expression equivalent.

  • templating - Many Jinja plugins (filters, lookups, tests) and methods previously silently ignored undefined inputs, which often masked subtle errors. Passing an undefined argument to a Jinja plugin or method that does not declare undefined support now results in an undefined value.

  • templating - Templates are always rendered in Jinja2 native mode. As a result, non-string values are no longer automatically converted to strings.

  • templating - Templates resulting in None are no longer automatically converted to an empty string.

  • templating - Templates with embedded inline templates that were not contained within a Jinja string constant now result in an error, as support for multi-pass templating was removed for security reasons. In most cases, such templates can be easily rewritten to avoid the use of embedded inline templates.

  • templating - The allow_unsafe_lookups option no longer has any effect. Lookup plugins are responsible for tagging strings containing templates to allow evaluation as a template.

  • templating - The result of the range() global function cannot be returned from a template- it should always be passed to a filter (e.g., random). Previously, range objects returned from an intermediate template were always converted to a list, which is inconsistent with inline consumption of range objects.

  • templating - #jinja2: overrides in templates with invalid override names or types are now templating errors.

  • postgresql_info - the db alias is deprecated and will be removed in the next major release, use the login_db argument instead.

  • postgresql_pg_hba - regarding #776 ‘keep_comments_at_rules’ has been deprecated and won’t do anything, the default is to keep the comments at the rules they are specified with. keep_comments_at_rules will be removed in 5.0.0 (https://github.com/ansible-collections/community.postgresql/pull/778)

  • postgresql_user - the db alias is deprecated and will be removed in the next major release, use the login_db argument instead.

  • Drop support for Ansible 2.9.

  • Drop support for Python 2.7 and 3.5.

Major Changes

  • Jinja plugins - Jinja builtin filter and test plugins are now accessible via their fully-qualified names ansible.builtin.{name}.

  • Task Execution / Forks - Forks no longer inherit stdio from the parent ansible-playbook process. stdout, stderr, and stdin within a worker are detached from the terminal, and non-functional. All needs to access stdio from a fork for controller side plugins requires use of Display.

  • ansible-test - Packages beneath module_utils can now contain __init__.py files.

  • variables - The type system underlying Ansible’s variable storage has been significantly overhauled and formalized. Attempts to store unsupported Python object types in variables will now result in an error.

  • variables - To support new Ansible features, many variable objects are now represented by subclasses of their respective native Python types. In most cases, they behave indistinguishably from their original types, but some Python libraries do not handle builtin object subclasses properly. Custom plugins that interact with such libraries may require changes to convert and pass the native types.

  • Bumping requires_ansible to >=2.16.0, since previous ansible-core versions are EoL now.

  • Bumping requires_ansible to >=2.16.0, since previous ansible-core versions are EoL now.

  • Bumping requires_ansible to >=2.16.0, since previous ansible-core versions are EoL now.

  • Bumping requires_ansible to >=2.16.0, since previous ansible-core versions are EoL now.

  • Bumping requires_ansible to >=2.16.0, since previous ansible-core versions are EoL now.

  • All Roles - Updated to support version 7.2

  • omevv_baseline_profile - This module allows to manage baseline profile.

  • omevv_baseline_profile_info - This module allows to retrieve baseline profile information.

  • omevv_compliance_info - This module allows to retrieve firmware compliance reports.

  • omevv_firmware - This module allows to update firmware of the single host and single cluster.

  • Support check_mode on all the configuration modules.

  • Supported new versions 7.6.1 and 7.6.2.

  • Updated the examples with correct values that have minimum or maximum values.

  • Bumping requires_ansible to >=2.16.0, since previous ansible-core versions are EoL now.

Removed Collections

  • cisco.asa (previously included version: 6.0.0)

  • community.network (previously included version: 5.1.0)

  • google.cloud (previously included version: 1.4.1)

  • ibm.spectrum_virtualize (previously included version: 2.0.0)

  • sensu.sensu_go (previously included version: 1.14.0)

You can still install a removed collection manually with ansible-galaxy collection install <name-of-collection>.

Removed Features

  • Remove deprecated plural form of collection path (https://github.com/ansible/ansible/pull/84156).

  • Removed deprecated STRING_CONVERSION_ACTION (https://github.com/ansible/ansible/issues/84220).

  • encrypt - passing unsupported passlib hashtype now raises AnsibleFilterError.

  • manager - remove deprecated include_delegate_to parameter from get_vars API.

  • modules - Modules returning non-UTF8 strings now result in an error. The MODULE_STRICT_UTF8_RESPONSE setting can be used to disable this check.

  • removed deprecated pycompat24 and compat.importlib.

  • selector - remove deprecated compat.selector related files (https://github.com/ansible/ansible/pull/84155).

  • windows - removed common module functions ConvertFrom-AnsibleJson, Format-AnsibleException from Windows modules as they are not used and add uneeded complexity to the code.

  • This release removes all deprecated plugins that have reached their end-of-life, including:

  • nxos_snmp_community

  • nxos_snmp_contact

  • nxos_snmp_host

  • nxos_snmp_location

  • nxos_snmp_user

  • This includes the following modules:

  • This release removes all deprecated plugins that have reached their end-of-life.

  • junos_scp

Deprecated Features

  • CLI - The --inventory-file option alias is deprecated. Use the -i or --inventory option instead.

  • Stategy Plugins - Use of strategy plugins not provided in ansible.builtin are deprecated and do not carry any backwards compatibility guarantees going forward. A future release will remove the ability to use external strategy plugins. No alternative for third party strategy plugins is currently planned.

  • ansible.module_utils.compat.datetime - The datetime compatibility shims are now deprecated. They are scheduled to be removed in ansible-core v2.21. This includes UTC, utcfromtimestamp() and utcnow importable from said module (https://github.com/ansible/ansible/pull/81874).

  • bool filter - Support for coercing unrecognized input values (including None) has been deprecated. Consult the filter documentation for acceptable values, or consider use of the truthy and falsy tests.

  • cache plugins - The ansible.plugins.cache.base Python module is deprecated. Use ansible.plugins.cache instead.

  • callback plugins - The v2_on_any callback method is deprecated. Use specific callback methods instead.

  • callback plugins - The v1 callback API (callback methods not prefixed with v2_) is deprecated. Use v2_ prefixed methods instead.

  • conditionals - Conditionals using Jinja templating delimiters (e.g., {{, {%) should be rewritten as expressions without delimiters, unless the entire conditional value is a single template that resolves to a trusted string expression. This is useful for dynamic indirection of conditional expressions, but is limited to trusted literal string expressions.

  • config - The ACTION_WARNINGS config has no effect. It previously disabled command warnings, which have since been removed.

  • config - The DEFAULT_JINJA2_NATIVE option has no effect. Jinja2 native mode is now the default and only option.

  • config - The DEFAULT_NULL_REPRESENTATION option has no effect. Null values are no longer automatically converted to another value during templating of single variable references.

  • display - The Display.get_deprecation_message method has been deprecated. Call Display.deprecated to display a deprecation message, or call it with removed=True to raise an AnsibleError.

  • file loading - Loading text files with DataLoader containing data that cannot be decoded under the expected encoding is deprecated. In most cases the encoding must be UTF-8, although some plugins allow choosing a different encoding. Previously, invalid data was silently wrapped in Unicode surrogate escape sequences, often resulting in later errors or other data corruption.

  • first_found lookup - Splitting of file paths on ,;: is deprecated. Pass a list of paths instead. The split method on strings can be used to split variables into a list as needed.

  • interpreter discovery - The auto_legacy and auto_legacy_silent options for INTERPRETER_PYTHON are deprecated. Use auto or auto_silent options instead, as they have the same effect.

  • oneline callback - The oneline callback and its associated ad-hoc CLI args (-o, --one-line) are deprecated.

  • paramiko - The paramiko connection plugin has been deprecated with planned removal in 2.21.

  • playbook variables - The play_hosts variable has been deprecated, use ansible_play_batch instead.

  • plugin error handling - The AnsibleError constructor arg suppress_extended_error is deprecated. Using suppress_extended_error=True has the same effect as show_content=False.

  • plugins - The listify_lookup_plugin_terms function is obsolete and in most cases no longer needed.

  • template lookup - The jinja2_native option is no longer used in the Ansible Core code base. Jinja2 native mode is now the default and only option.

  • templating - Support for enabling Jinja2 extensions (not plugins) has been deprecated.

  • templating - The ansible_managed variable available for certain templating scenarios, such as the template action and template lookup has been deprecated. Define and use a custom variable instead of relying on ansible_managed.

  • templating - The disable_lookups option has no effect, since plugins must be updated to apply trust before any templating can be performed.

  • to_yaml/to_nice_yaml filters - Implicit YAML dumping of vaulted value ciphertext is deprecated. Set dump_vault_tags to explicitly specify the desired behavior.

  • tree callback - The tree callback and its associated ad-hoc CLI args (-t, --tree) are deprecated.

  • autoscaling_group - the decrement_desired_capacity parameter has been deprecated and will be removed in release 14.0.0 of this collection. Management of instances attached an autoscaling group can be performed using the amazon.aws.autoscaling_instance module (https://github.com/ansible-collections/amazon.aws/pull/2396).

  • autoscaling_group - the replace_batch_size, lc_check and lt_check parameters have been deprecated and will be removed in release 14.0.0 of this collection. Rolling replacement of instances in an autoscaling group can be performed using the amazon.aws.autoscaling_instance_refresh module (https://github.com/ansible-collections/amazon.aws/pull/2396).

  • autoscaling_group - the functionality provided through the detach_instances parameter has been deprecated and will be removed in release 14.0.0 of this collection. Management of instances attached an autoscaling group can be performed using the amazon.aws.autoscaling_instance module (https://github.com/ansible-collections/amazon.aws/pull/2396).

  • autoscaling_group - the functionality provided through the replace_all_instances parameter has been deprecated and will be removed in release 14.0.0 of this collection. Rolling replacement of instances in an autoscaling group can be performed using the amazon.aws.autoscaling_instance_refresh module (https://github.com/ansible-collections/amazon.aws/pull/2396).

  • autoscaling_group - the functionality provided through the replace_instances parameter has been deprecated and will be removed in release 14.0.0 of this collection. Management of instances attached an autoscaling group can be performed using the amazon.aws.autoscaling_instance module (https://github.com/ansible-collections/amazon.aws/pull/2396).

  • Added deprecation warnings for the above plugins, displayed when running respective filter plugins.

  • parse_cli_textfsm filter plugin is deprecated and will be removed in a future release after 2027-02-01. Use ansible.utils.cli_parse with the ansible.utils.textfsm_parser parser as a replacement.

  • parse_cli filter plugin is deprecated and will be removed in a future release after 2027-02-01. Use ansible.utils.cli_parse as a replacement.

  • parse_xml filter plugin is deprecated and will be removed in a future release after 2027-02-01. Use ansible.utils.cli_parse with the ansible.utils.xml_parser parser as a replacement.

  • ios_vlans - deprecate mtu, please use ios_interfaces to configure mtu to the interface where vlans is applied.

  • postgresql_copy - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_db - the rename choice of the state option is deprecated and will be removed in version 5.0.0, use the postgresql_query module instead.

  • postgresql_ext - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_idx - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_membership - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_owner - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_ping - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_privs - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_publication - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_query - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_schema - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_script - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_sequence - the rename_to option is deprecated and will be removed in version 5.0.0, use the postgresql_query module instead.

  • postgresql_sequence - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_set - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_slot - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_subscription - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_table - the rename option is deprecated and will be removed in version 5.0.0, use the postgresql_query module instead.

  • postgresql_table - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_tablespace - the rename_to option is deprecated and will be removed in version 5.0.0, use the postgresql_query module instead.

  • postgresql_tablespace - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • postgresql_user_obj_stat_info - the parameter aliases db and database are deprecated and will be removed in community.postgresql 5.0.0. Use login_db instead.

  • content_library_item_info - the module has been deprecated and will be removed in vmware.vmware_rest 5.0.0