From f4b6b72c5b009d6b9eb947382b38f3e337d264b7 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Tue, 31 Jan 2017 15:35:28 -0500 Subject: [PATCH] Warn reserved (#20567) * removed unused vars * added warning when using reserved vars fixes #4816 * cleanup --- lib/ansible/executor/task_queue_manager.py | 2 + lib/ansible/vars/__init__.py | 7 +- lib/ansible/vars/reserved.py | 77 ++++++++++++++++++++++ 3 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 lib/ansible/vars/reserved.py diff --git a/lib/ansible/executor/task_queue_manager.py b/lib/ansible/executor/task_queue_manager.py index dbf66c96086..a68eb70a381 100644 --- a/lib/ansible/executor/task_queue_manager.py +++ b/lib/ansible/executor/task_queue_manager.py @@ -36,6 +36,7 @@ from ansible.plugins.callback import CallbackBase from ansible.template import Templar from ansible.utils.helpers import pct_to_int from ansible.vars.hostvars import HostVars +from ansible.vars.reserved import warn_if_reserved try: from __main__ import display @@ -209,6 +210,7 @@ class TaskQueueManager: self.load_callbacks() all_vars = self._variable_manager.get_vars(loader=self._loader, play=play) + warn_if_reserved(all_vars) templar = Templar(loader=self._loader, variables=all_vars) new_play = play.copy() diff --git a/lib/ansible/vars/__init__.py b/lib/ansible/vars/__init__.py index cc987315cda..7c423b503b0 100644 --- a/lib/ansible/vars/__init__.py +++ b/lib/ansible/vars/__init__.py @@ -92,6 +92,7 @@ def strip_internal_keys(dirty): clean[k] = strip_internal_keys(dirty[k]) return clean + class VariableManager: def __init__(self): @@ -315,10 +316,10 @@ class VariableManager: for item in data: all_vars = combine_vars(all_vars, item) break - except AnsibleFileNotFound as e: + except AnsibleFileNotFound: # we continue on loader failures continue - except AnsibleParserError as e: + except AnsibleParserError: raise else: # if include_delegate_to is set to False, we ignore the missing @@ -456,7 +457,7 @@ class VariableManager: try: loop_terms = listify_lookup_plugin_terms(terms=task.loop_args, templar=templar, loader=loader, fail_on_undefined=True, convert_bare=False) items = lookup_loader.get(task.loop, loader=loader, templar=templar).run(terms=loop_terms, variables=vars_copy) - except AnsibleUndefinedVariable as e: + except AnsibleUndefinedVariable: # This task will be skipped later due to this, so we just setup # a dummy array for the later code so it doesn't fail items = [None] diff --git a/lib/ansible/vars/reserved.py b/lib/ansible/vars/reserved.py new file mode 100644 index 00000000000..ec178ec2a6d --- /dev/null +++ b/lib/ansible/vars/reserved.py @@ -0,0 +1,77 @@ +# (c) 2017 Ansible By Red Hat +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.playbook import Play +from ansible.playbook.block import Block +from ansible.playbook.role import Role +from ansible.playbook.task import Task + +try: + from __main__ import display +except ImportError: + from ansible.utils.display import Display + display = Display() + +def get_reserved_names(include_private=True): + ''' this function returns the list of reserved names associated with play objects''' + + public = set() + private = set() + result = set() + + #FIXME: find a way to 'not hardcode', possibly need role deps/includes + class_list = [ Play, Role, Block, Task ] + + for aclass in class_list: + aobj = aclass() + + # build ordered list to loop over and dict with attributes + for attribute in aobj.__dict__['_attributes']: + if 'private' in attribute: + private.add(attribute) + else: + public.add(attribute) + + # local_action is implicit with action + if 'action' in public: + public.add('local_action') + + # loop implies with_ + #FIXME: remove after with_ is not only deprecated but removed + if 'loop' in private or 'loop' in public: + public.add('with_') + + if include_private: + result = public.union(private) + else: + result = public + + return result + +def warn_if_reserved(myvars): + ''' this function warns if any variable passed conflicts with internally reserved names ''' + reserved = get_reserved_names() + for varname in myvars: + if varname == 'vars': + continue # we add this one internally + if varname in reserved: + display.warning('Found variable using reserved name: %s' % varname) +