summaryrefslogtreecommitdiff
path: root/lib/ansible/playbook
diff options
context:
space:
mode:
authorBrian Coca <brian.coca+git@gmail.com>2015-12-09 07:21:00 -0800
committerBrian Coca <brian.coca+git@gmail.com>2015-12-09 07:29:36 -0800
commit87969868d42cd8aba1c65c8207d059d73407373b (patch)
tree45c83b19f6605d38caebe03e5d374b59c85b399f /lib/ansible/playbook
parent0719eb3e2d798c6f80223e37dd77bc0ac41c537d (diff)
downloadansible-87969868d42cd8aba1c65c8207d059d73407373b.tar.gz
avoid persistent containers in attribute defaults
moved from the field attribute declaration and created a placeholder which then is resolved in the field attribute class. this is to avoid unwanted persistent of the defaults across objects which introduces stealth bugs when multiple objects of the same kind are used in succession while not overriding the default values.
Diffstat (limited to 'lib/ansible/playbook')
-rw-r--r--lib/ansible/playbook/attribute.py11
-rw-r--r--lib/ansible/playbook/block.py6
-rw-r--r--lib/ansible/playbook/conditional.py2
-rw-r--r--lib/ansible/playbook/play.py16
-rw-r--r--lib/ansible/playbook/play_context.py4
-rw-r--r--lib/ansible/playbook/playbook_include.py2
-rw-r--r--lib/ansible/playbook/role/metadata.py2
-rw-r--r--lib/ansible/playbook/taggable.py2
-rw-r--r--lib/ansible/playbook/task.py2
9 files changed, 29 insertions, 18 deletions
diff --git a/lib/ansible/playbook/attribute.py b/lib/ansible/playbook/attribute.py
index 703d9dbca1..ce7ed6d8fe 100644
--- a/lib/ansible/playbook/attribute.py
+++ b/lib/ansible/playbook/attribute.py
@@ -32,6 +32,17 @@ class Attribute:
self.priority = priority
self.always_post_validate = always_post_validate
+ # This is here to avoid `default=<container>` unwanted persistence across object instances
+ # We cannot rely on None as some fields use it to skip the code
+ # that would detect an empty container as a user error
+ if self.default == '_ansible_container':
+ if self.isa == 'list':
+ self.default = []
+ elif self.isa == 'dict':
+ self.default = {}
+ elif self.isa == 'set':
+ self.default = set()
+
def __eq__(self, other):
return other.priority == self.priority
diff --git a/lib/ansible/playbook/block.py b/lib/ansible/playbook/block.py
index f2d9c82833..66009b028a 100644
--- a/lib/ansible/playbook/block.py
+++ b/lib/ansible/playbook/block.py
@@ -30,9 +30,9 @@ from ansible.playbook.taggable import Taggable
class Block(Base, Become, Conditional, Taggable):
- _block = FieldAttribute(isa='list', default=[])
- _rescue = FieldAttribute(isa='list', default=[])
- _always = FieldAttribute(isa='list', default=[])
+ _block = FieldAttribute(isa='list', default='_ansible_container')
+ _rescue = FieldAttribute(isa='list', default='_ansible_container')
+ _always = FieldAttribute(isa='list', default='_ansible_container')
_delegate_to = FieldAttribute(isa='list')
_delegate_facts = FieldAttribute(isa='bool', default=False)
diff --git a/lib/ansible/playbook/conditional.py b/lib/ansible/playbook/conditional.py
index fc178e2fa1..a5b3ca725f 100644
--- a/lib/ansible/playbook/conditional.py
+++ b/lib/ansible/playbook/conditional.py
@@ -33,7 +33,7 @@ class Conditional:
to be run conditionally when a condition is met or skipped.
'''
- _when = FieldAttribute(isa='list', default=[])
+ _when = FieldAttribute(isa='list', default='_ansible_container')
def __init__(self, loader=None):
# when used directly, this class needs a loader, but we want to
diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py
index ed61416e95..e08c8c6001 100644
--- a/lib/ansible/playbook/play.py
+++ b/lib/ansible/playbook/play.py
@@ -64,22 +64,22 @@ class Play(Base, Taggable, Become):
# Connection
_gather_facts = FieldAttribute(isa='bool', default=None, always_post_validate=True)
- _hosts = FieldAttribute(isa='list', default=[], required=True, listof=string_types, always_post_validate=True)
+ _hosts = FieldAttribute(isa='list', default='_ansible_container', required=True, listof=string_types, always_post_validate=True)
_name = FieldAttribute(isa='string', default='', always_post_validate=True)
# Variable Attributes
- _vars_files = FieldAttribute(isa='list', default=[], priority=99)
- _vars_prompt = FieldAttribute(isa='list', default=[], always_post_validate=True)
+ _vars_files = FieldAttribute(isa='list', default='_ansible_container', priority=99)
+ _vars_prompt = FieldAttribute(isa='list', default='_ansible_container', always_post_validate=True)
_vault_password = FieldAttribute(isa='string', always_post_validate=True)
# Role Attributes
- _roles = FieldAttribute(isa='list', default=[], priority=90)
+ _roles = FieldAttribute(isa='list', default='_ansible_container', priority=90)
# Block (Task) Lists Attributes
- _handlers = FieldAttribute(isa='list', default=[])
- _pre_tasks = FieldAttribute(isa='list', default=[])
- _post_tasks = FieldAttribute(isa='list', default=[])
- _tasks = FieldAttribute(isa='list', default=[])
+ _handlers = FieldAttribute(isa='list', default='_ansible_container')
+ _pre_tasks = FieldAttribute(isa='list', default='_ansible_container')
+ _post_tasks = FieldAttribute(isa='list', default='_ansible_container')
+ _tasks = FieldAttribute(isa='list', default='_ansible_container')
# Flag/Setting Attributes
_any_errors_fatal = FieldAttribute(isa='bool', default=False, always_post_validate=True)
diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py
index 81223500ad..da291c3c83 100644
--- a/lib/ansible/playbook/play_context.py
+++ b/lib/ansible/playbook/play_context.py
@@ -171,8 +171,8 @@ class PlayContext(Base):
# general flags
_verbosity = FieldAttribute(isa='int', default=0)
- _only_tags = FieldAttribute(isa='set', default=set())
- _skip_tags = FieldAttribute(isa='set', default=set())
+ _only_tags = FieldAttribute(isa='set', default='_ansible_container')
+ _skip_tags = FieldAttribute(isa='set', default='_ansible_container')
_check_mode = FieldAttribute(isa='bool', default=False)
_force_handlers = FieldAttribute(isa='bool', default=False)
_start_at_task = FieldAttribute(isa='string')
diff --git a/lib/ansible/playbook/playbook_include.py b/lib/ansible/playbook/playbook_include.py
index d9af2ba523..52081c4153 100644
--- a/lib/ansible/playbook/playbook_include.py
+++ b/lib/ansible/playbook/playbook_include.py
@@ -35,7 +35,7 @@ class PlaybookInclude(Base, Conditional, Taggable):
_name = FieldAttribute(isa='string')
_include = FieldAttribute(isa='string')
- _vars = FieldAttribute(isa='dict', default=dict())
+ _vars = FieldAttribute(isa='dict', default='_ansible_container')
@staticmethod
def load(data, basedir, variable_manager=None, loader=None):
diff --git a/lib/ansible/playbook/role/metadata.py b/lib/ansible/playbook/role/metadata.py
index 58b59145a1..4bb7d0ce02 100644
--- a/lib/ansible/playbook/role/metadata.py
+++ b/lib/ansible/playbook/role/metadata.py
@@ -40,7 +40,7 @@ class RoleMetadata(Base):
'''
_allow_duplicates = FieldAttribute(isa='bool', default=False)
- _dependencies = FieldAttribute(isa='list', default=[])
+ _dependencies = FieldAttribute(isa='list', default='_ansible_container')
_galaxy_info = FieldAttribute(isa='GalaxyInfo')
def __init__(self, owner=None):
diff --git a/lib/ansible/playbook/taggable.py b/lib/ansible/playbook/taggable.py
index 8f5cfa0934..37e3261e80 100644
--- a/lib/ansible/playbook/taggable.py
+++ b/lib/ansible/playbook/taggable.py
@@ -29,7 +29,7 @@ from ansible.template import Templar
class Taggable:
untagged = frozenset(['untagged'])
- _tags = FieldAttribute(isa='list', default=[], listof=(string_types,int))
+ _tags = FieldAttribute(isa='list', default='_ansible_container', listof=(string_types,int))
def __init__(self):
super(Taggable, self).__init__()
diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py
index 17f1952e39..53a9a3c393 100644
--- a/lib/ansible/playbook/task.py
+++ b/lib/ansible/playbook/task.py
@@ -64,7 +64,7 @@ class Task(Base, Conditional, Taggable, Become):
# will be used if defined
# might be possible to define others
- _args = FieldAttribute(isa='dict', default=dict())
+ _args = FieldAttribute(isa='dict', default='_ansible_container')
_action = FieldAttribute(isa='string')
_any_errors_fatal = FieldAttribute(isa='bool')