From 75ad1f8d6ac29ec0ba8d46ef2ce13c75aef41f35 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Fri, 22 Aug 2025 15:35:09 -0400 Subject: [PATCH] tags warn wwhen using reserved tags (#85631) --- changelogs/fragments/tag_u_it.yml | 2 ++ changelogs/fragments/warn_reserved_tags.yml | 2 ++ lib/ansible/playbook/taggable.py | 21 ++++++++++++++----- test/integration/targets/tags/runme.sh | 6 +++++- .../targets/tags/warn_reserved.yml | 6 ++++++ 5 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/tag_u_it.yml create mode 100644 changelogs/fragments/warn_reserved_tags.yml create mode 100644 test/integration/targets/tags/warn_reserved.yml diff --git a/changelogs/fragments/tag_u_it.yml b/changelogs/fragments/tag_u_it.yml new file mode 100644 index 00000000000..e32088e9e89 --- /dev/null +++ b/changelogs/fragments/tag_u_it.yml @@ -0,0 +1,2 @@ +minor_changes: + - tags now warn when using reserved keywords. diff --git a/changelogs/fragments/warn_reserved_tags.yml b/changelogs/fragments/warn_reserved_tags.yml new file mode 100644 index 00000000000..b21014cd330 --- /dev/null +++ b/changelogs/fragments/warn_reserved_tags.yml @@ -0,0 +1,2 @@ +minor_changes: + - ansible now warns if you use reserved tags that were only meant for selection and not for use in play. diff --git a/lib/ansible/playbook/taggable.py b/lib/ansible/playbook/taggable.py index 5823b775947..98d91cac65e 100644 --- a/lib/ansible/playbook/taggable.py +++ b/lib/ansible/playbook/taggable.py @@ -19,11 +19,14 @@ from __future__ import annotations import typing as t +from ansible._internal._templating._engine import TemplateEngine from ansible.errors import AnsibleError from ansible.module_utils.common.sentinel import Sentinel from ansible.module_utils._internal._datatag import AnsibleTagHelper from ansible.playbook.attribute import FieldAttribute -from ansible._internal._templating._engine import TemplateEngine +from ansible.utils.display import Display + +_display = Display() def _flatten_tags(tags: list[str | int]) -> list[str | int]: @@ -38,17 +41,25 @@ def _flatten_tags(tags: list[str | int]) -> list[str | int]: class Taggable: + _RESERVED = frozenset(['tagged', 'all', 'untagged']) untagged = frozenset(['untagged']) tags = FieldAttribute(isa='list', default=list, listof=(str, int), extend=True) def _load_tags(self, attr, ds): + + tags = None if isinstance(ds, list): - return ds + tags = ds + elif isinstance(ds, str): + tags = [AnsibleTagHelper.tag_copy(ds, item.strip()) for item in ds.split(',')] + + if tags is None: + raise AnsibleError('tags must be specified as a list', obj=ds) - if isinstance(ds, str): - return [AnsibleTagHelper.tag_copy(ds, item.strip()) for item in ds.split(',')] + if found := self._RESERVED.intersection(tags): + _display.warning(f"Found reserved tagnames in tags: {list(found)!r}, we do not recommend doing this as it might give unexpected results", obj=ds) - raise AnsibleError('tags must be specified as a list', obj=ds) + return tags def _get_all_taggable_objects(self) -> t.Iterable[Taggable]: obj = self diff --git a/test/integration/targets/tags/runme.sh b/test/integration/targets/tags/runme.sh index 3e0828f5d2c..fb7951f5594 100755 --- a/test/integration/targets/tags/runme.sh +++ b/test/integration/targets/tags/runme.sh @@ -99,4 +99,8 @@ ansible-playbook test_template_role_tags.yml --tags tag1 "$@" 2>&1 | tee out.txt [ "$(grep out.txt -ce 'Tagged_task')" = "1" ]; rm out.txt ansible-playbook test_template_role_tags.yml --skip-tags tag1 "$@" 2>&1 | tee out.txt -[ "$(grep out.txt -ce 'Tagged_task')" = "0" ]; rm out.txt +[ "$(grep out.txt -ce 'Tagged_task')" = "0" ]; +[ "$(grep out.txt -ce 'Found reserved tagsnames')" = "0" ]; rm out.txt + +ansible-playbook warn_reserved.yml "$@" 2>&1 | tee out.txt +[ "$(grep out.txt -ce 'Found reserved tagnames')" = "1" ]; rm out.txt diff --git a/test/integration/targets/tags/warn_reserved.yml b/test/integration/targets/tags/warn_reserved.yml new file mode 100644 index 00000000000..1adee2cf505 --- /dev/null +++ b/test/integration/targets/tags/warn_reserved.yml @@ -0,0 +1,6 @@ +- hosts: all + gather_facts: false + tasks: + - debug: msg=not tagged + - debug: msg=taggged + tags: tagged