mirror of https://github.com/ansible/ansible.git
Prevent template lookup and action from masking `ansible_managed` value (#85075)
* deprecate DEFAULT_MANAGED_STR and prevent masking of ansible_managed var * adjust public API behavior * restore backward-compatible behavior on existing public APIpull/83775/merge
parent
2b7204527b
commit
9f0a8075e3
@ -0,0 +1,3 @@
|
||||
minor_changes:
|
||||
- template action and lookup plugin - The value of the ``ansible_managed`` variable (if set) will not be masked by the ``template`` action and lookup.
|
||||
Previously, the value calculated by the ``DEFAULT_MANAGED_STR`` configuration option always masked the variable value during plugin execution, preventing runtime customization.
|
||||
@ -0,0 +1,72 @@
|
||||
from __future__ import annotations as _annotations
|
||||
|
||||
import datetime as _datetime
|
||||
import os as _os
|
||||
import pwd as _pwd
|
||||
import time as _time
|
||||
|
||||
from ansible import constants as _constants
|
||||
from ansible.module_utils._internal import _datatag
|
||||
|
||||
|
||||
def generate_ansible_template_vars(
|
||||
path: str,
|
||||
fullpath: str | None = None,
|
||||
dest_path: str | None = None,
|
||||
include_ansible_managed: bool = True,
|
||||
) -> dict[str, object]:
|
||||
"""
|
||||
Generate and return a dictionary with variable metadata about the template specified by `fullpath`.
|
||||
If `fullpath` is `None`, `path` will be used instead.
|
||||
"""
|
||||
# deprecated description="update the ansible.windows collection to inline this logic instead of calling this internal function" core_version="2.23"
|
||||
if fullpath is None:
|
||||
fullpath = _os.path.abspath(path)
|
||||
|
||||
template_path = fullpath
|
||||
template_stat = _os.stat(template_path)
|
||||
|
||||
template_uid: int | str
|
||||
|
||||
try:
|
||||
template_uid = _pwd.getpwuid(template_stat.st_uid).pw_name
|
||||
except KeyError:
|
||||
template_uid = template_stat.st_uid
|
||||
|
||||
temp_vars = dict(
|
||||
template_host=_os.uname()[1],
|
||||
template_path=path,
|
||||
template_mtime=_datetime.datetime.fromtimestamp(template_stat.st_mtime),
|
||||
template_uid=template_uid,
|
||||
template_run_date=_datetime.datetime.now(),
|
||||
template_destpath=dest_path,
|
||||
template_fullpath=fullpath,
|
||||
)
|
||||
|
||||
if include_ansible_managed: # only inject the config default value if the variable wasn't set
|
||||
temp_vars['ansible_managed'] = _generate_ansible_managed(template_stat)
|
||||
|
||||
return temp_vars
|
||||
|
||||
|
||||
def _generate_ansible_managed(template_stat: _os.stat_result) -> str:
|
||||
"""Generate and return the `ansible_managed` variable."""
|
||||
# deprecated description="remove the `_generate_ansible_managed` function and use a constant instead" core_version="2.23"
|
||||
|
||||
from ansible.template import trust_as_template
|
||||
|
||||
managed_default = _constants.config.get_config_value('DEFAULT_MANAGED_STR')
|
||||
|
||||
managed_str = managed_default.format(
|
||||
# IMPORTANT: These values must be constant strings to avoid template injection.
|
||||
# Use Jinja template expressions where variables are needed.
|
||||
host="{{ template_host }}",
|
||||
uid="{{ template_uid }}",
|
||||
file="{{ template_path }}",
|
||||
)
|
||||
|
||||
ansible_managed = _time.strftime(managed_str, _time.localtime(template_stat.st_mtime))
|
||||
ansible_managed = _datatag.AnsibleTagHelper.tag_copy(managed_default, ansible_managed)
|
||||
ansible_managed = trust_as_template(ansible_managed)
|
||||
|
||||
return ansible_managed
|
||||
@ -0,0 +1,18 @@
|
||||
# deprecated: description='ansible_managed has been removed' core_version='2.23'
|
||||
- name: invoke template lookup with content using default injected `ansible_managed`
|
||||
debug:
|
||||
msg: "{{ lookup('template', 'uses_ansible_managed.j2') }}"
|
||||
register: default_lookup_result
|
||||
|
||||
- name: invoke template lookup with content using explicitly set `ansible_managed` var
|
||||
vars:
|
||||
ansible_managed: '{{ "a " ~ "dynamic " ~ "ansible_managed value" }}'
|
||||
debug:
|
||||
msg: "{{ lookup('template', 'uses_ansible_managed.j2') }}"
|
||||
register: overridden_lookup_result
|
||||
|
||||
- name: validate ansible_managed results
|
||||
assert:
|
||||
that:
|
||||
- default_lookup_result.msg is contains "Ansible managed"
|
||||
- overridden_lookup_result.msg is contains "a dynamic ansible_managed value"
|
||||
@ -0,0 +1 @@
|
||||
{{ ansible_managed }}
|
||||
@ -0,0 +1,20 @@
|
||||
# deprecated: description='ansible_managed has been removed' core_version='2.23'
|
||||
- name: invoke template action with content using default injected `ansible_managed`
|
||||
template:
|
||||
src: uses_ansible_managed.j2
|
||||
dest: '{{output_dir}}/default_am.txt'
|
||||
register: default_action_result
|
||||
|
||||
- name: invoke template action with content using explicitly set `ansible_managed` var
|
||||
vars:
|
||||
ansible_managed: '{{ "a " ~ "dynamic " ~ "ansible_managed value" }}'
|
||||
template:
|
||||
src: uses_ansible_managed.j2
|
||||
dest: '{{output_dir}}/overridden_am.txt'
|
||||
register: overridden_action_result
|
||||
|
||||
- name: validate ansible_managed results
|
||||
assert:
|
||||
that:
|
||||
- lookup('file', default_action_result.dest) is contains "Ansible managed"
|
||||
- lookup('file', overridden_action_result.dest) is contains "a dynamic ansible_managed value"
|
||||
@ -0,0 +1 @@
|
||||
{{ ansible_managed }}
|
||||
Loading…
Reference in New Issue