summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cammarata <jimi@sngx.net>2016-08-25 11:34:08 -0500
committerJames Cammarata <jimi@sngx.net>2016-08-25 13:46:53 -0500
commitafb4eb25586d52205bb16eff7a4ecc27ca2ebd85 (patch)
tree90893748e3d8c373a52f84c85fe5c53f6a987a1b
parent588c0b0e5ea9dc3d31d8a827299f123d2877778e (diff)
downloadansible-meta_meta_meta.tar.gz
Some further cleanup in the meta branchmeta_meta_meta
* adds squashing to objects, which allows them to be squashed down to a final "view" before post_validate to avoid expensive evaluations of parent attributes
-rw-r--r--lib/ansible/executor/task_executor.py2
-rw-r--r--lib/ansible/playbook/base.py41
-rw-r--r--lib/ansible/playbook/become.py26
-rw-r--r--lib/ansible/playbook/block.py81
-rw-r--r--lib/ansible/playbook/task.py26
5 files changed, 78 insertions, 98 deletions
diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py
index 7b0802bcb2..ce5c8dba33 100644
--- a/lib/ansible/executor/task_executor.py
+++ b/lib/ansible/executor/task_executor.py
@@ -72,6 +72,8 @@ class TaskExecutor:
self._connection = None
self._rslt_q = rslt_q
+ self._task.squash()
+
def run(self):
'''
The main executor entrypoint, where we determine if the specified
diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py
index 2447a72824..e95e16b518 100644
--- a/lib/ansible/playbook/base.py
+++ b/lib/ansible/playbook/base.py
@@ -24,7 +24,7 @@ import itertools
import operator
import uuid
-from copy import deepcopy
+from copy import copy as shallowcopy, deepcopy
from functools import partial
from inspect import getmembers
@@ -53,8 +53,10 @@ def _generic_g(prop_name, self):
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
def _generic_g_method(prop_name, self):
- method = "_get_attr_%s" % prop_name
try:
+ if self._squashed:
+ return self._attributes[prop_name]
+ method = "_get_attr_%s" % prop_name
return getattr(self, method)()
except KeyError:
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
@@ -62,7 +64,7 @@ def _generic_g_method(prop_name, self):
def _generic_g_parent(prop_name, self):
try:
value = self._attributes[prop_name]
- if value is None and not self._finalized:
+ if value is None and not self._squashed and not self._finalized:
try:
value = self._get_parent_attribute(prop_name)
except AttributeError:
@@ -106,10 +108,13 @@ class BaseMeta(type):
# its value from a parent object
method = "_get_attr_%s" % attr_name
if method in src_dict or method in dst_dict:
+ #print("^ assigning generic_g_method to %s" % attr_name)
getter = partial(_generic_g_method, attr_name)
- elif ('_get_parent_attribute' in src_dict or '_get_parent_attribute' in dst_dict) and value.inherit:
+ elif '_get_parent_attribute' in dst_dict and value.inherit:
+ #print("^ assigning generic_g_parent to %s" % attr_name)
getter = partial(_generic_g_parent, attr_name)
else:
+ #print("^ assigning generic_g to %s" % attr_name)
getter = partial(_generic_g, attr_name)
setter = partial(_generic_s, attr_name)
@@ -135,6 +140,7 @@ class BaseMeta(type):
# now create the attributes based on the FieldAttributes
# available, including from parent (and grandparent) objects
+ #print("creating class %s" % name)
_create_attrs(dct, dct)
_process_parents(parents, dct)
@@ -148,7 +154,7 @@ class Base(with_metaclass(BaseMeta, object)):
_remote_user = FieldAttribute(isa='string')
# variables
- _vars = FieldAttribute(isa='dict', priority=100)
+ _vars = FieldAttribute(isa='dict', priority=100, inherit=False)
# flags and misc. settings
_environment = FieldAttribute(isa='list')
@@ -173,6 +179,7 @@ class Base(with_metaclass(BaseMeta, object)):
# other internal params
self._validated = False
+ self._squashed = False
self._finalized = False
# every object gets a random uuid:
@@ -297,6 +304,22 @@ class Base(with_metaclass(BaseMeta, object)):
self._validated = True
+ def squash(self):
+ '''
+ Evaluates all attributes and sets them to the evaluated version,
+ so that all future accesses of attributes do not need to evaluate
+ parent attributes.
+ '''
+ if not self._squashed:
+ for name in self._valid_attrs.keys():
+ getter = partial(_generic_g, name)
+ setter = partial(_generic_s, name)
+ deleter = partial(_generic_d, name)
+
+ self._attributes[name] = getattr(self, name)
+ #print("squashed attr %s: %s" % (name, self._attributes[name]))
+ self._squashed = True
+
def copy(self):
'''
Create a copy of this object and return it.
@@ -305,13 +328,7 @@ class Base(with_metaclass(BaseMeta, object)):
new_me = self.__class__()
for name in self._valid_attrs.keys():
- attr_val = getattr(self, name)
- if isinstance(attr_val, collections.Sequence):
- setattr(new_me, name, attr_val[:])
- elif isinstance(attr_val, collections.Mapping):
- setattr(new_me, name, attr_val.copy())
- else:
- setattr(new_me, name, attr_val)
+ new_me._attributes[name] = shallowcopy(self._attributes[name])
new_me._loader = self._loader
new_me._variable_manager = self._variable_manager
diff --git a/lib/ansible/playbook/become.py b/lib/ansible/playbook/become.py
index a2d1109cfc..c43c91ce45 100644
--- a/lib/ansible/playbook/become.py
+++ b/lib/ansible/playbook/become.py
@@ -101,29 +101,3 @@ class Become:
if become_user is None:
become_user = C.DEFAULT_BECOME_USER
- def _get_attr_become(self):
- '''
- Override for the 'become' getattr fetcher, used from Base.
- '''
- if hasattr(self, '_get_parent_attribute'):
- return self._get_parent_attribute('become')
- else:
- return self._attributes['become']
-
- def _get_attr_become_method(self):
- '''
- Override for the 'become_method' getattr fetcher, used from Base.
- '''
- if hasattr(self, '_get_parent_attribute'):
- return self._get_parent_attribute('become_method')
- else:
- return self._attributes['become_method']
-
- def _get_attr_become_user(self):
- '''
- Override for the 'become_user' getattr fetcher, used from Base.
- '''
- if hasattr(self, '_get_parent_attribute'):
- return self._get_parent_attribute('become_user')
- else:
- return self._attributes['become_user']
diff --git a/lib/ansible/playbook/block.py b/lib/ansible/playbook/block.py
index cde41172f6..29f8742165 100644
--- a/lib/ansible/playbook/block.py
+++ b/lib/ansible/playbook/block.py
@@ -278,6 +278,9 @@ class Block(Base, Become, Conditional, Taggable):
for dep in dep_chain:
dep.set_loader(loader)
+ def _get_attr_environment(self):
+ return self._get_parent_attribute('environment', extend=True)
+
def _get_parent_attribute(self, attr, extend=False):
'''
Generic logic to get the attribute or parent attribute for a block value.
@@ -288,50 +291,50 @@ class Block(Base, Become, Conditional, Taggable):
value = self._attributes[attr]
if self._parent and (value is None or extend):
- parent_value = getattr(self._parent, attr, None)
- if extend:
- value = self._extend_value(value, parent_value)
- else:
- value = parent_value
- if self._role and (value is None or extend) and hasattr(self._role, attr):
- parent_value = getattr(self._role, attr, None)
- if extend:
- value = self._extend_value(value, parent_value)
- else:
- value = parent_value
-
- dep_chain = self.get_dep_chain()
- if dep_chain and (value is None or extend):
- dep_chain.reverse()
- for dep in dep_chain:
- dep_value = getattr(dep, attr, None)
- if extend:
- value = self._extend_value(value, dep_value)
- else:
- value = dep_value
-
- if value is not None and not extend:
- break
- if self._play and (value is None or extend) and hasattr(self._play, attr):
- parent_value = getattr(self._play, attr, None)
- if extend:
- value = self._extend_value(value, parent_value)
- else:
- value = parent_value
+ try:
+ parent_value = getattr(self._parent, attr, None)
+ if extend:
+ value = self._extend_value(value, parent_value)
+ else:
+ value = parent_value
+ except AttributeError:
+ pass
+ if self._role and (value is None or extend):
+ try:
+ parent_value = getattr(self._role, attr, None)
+ if extend:
+ value = self._extend_value(value, parent_value)
+ else:
+ value = parent_value
+
+ dep_chain = self.get_dep_chain()
+ if dep_chain and (value is None or extend):
+ dep_chain.reverse()
+ for dep in dep_chain:
+ dep_value = getattr(dep, attr, None)
+ if extend:
+ value = self._extend_value(value, dep_value)
+ else:
+ value = dep_value
+
+ if value is not None and not extend:
+ break
+ except AttributeError:
+ pass
+ if self._play and (value is None or extend):
+ try:
+ parent_value = getattr(self._play, attr, None)
+ if extend:
+ value = self._extend_value(value, parent_value)
+ else:
+ value = parent_value
+ except AttributeError:
+ pass
except KeyError as e:
pass
return value
- def _get_attr_environment(self):
- return self._get_parent_attribute('environment')
-
- def _get_attr_any_errors_fatal(self):
- '''
- Override for the 'tags' getattr fetcher, used from Base.
- '''
- return self._get_parent_attribute('any_errors_fatal')
-
def filter_tagged_tasks(self, play_context, all_vars):
'''
Creates a new block, with task lists filtered based on the tags contained
diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py
index 9c6e91b15f..e99f84c108 100644
--- a/lib/ansible/playbook/task.py
+++ b/lib/ansible/playbook/task.py
@@ -79,9 +79,9 @@ class Task(Base, Conditional, Taggable, Become):
_delegate_facts = FieldAttribute(isa='bool', default=False)
_failed_when = FieldAttribute(isa='list', default=[])
_first_available_file = FieldAttribute(isa='list')
- _loop = FieldAttribute(isa='string', private=True)
- _loop_args = FieldAttribute(isa='list', private=True)
- _loop_control = FieldAttribute(isa='class', class_type=LoopControl)
+ _loop = FieldAttribute(isa='string', private=True, inherit=False)
+ _loop_args = FieldAttribute(isa='list', private=True, inherit=False)
+ _loop_control = FieldAttribute(isa='class', class_type=LoopControl, inherit=False)
_name = FieldAttribute(isa='string', default='')
_notify = FieldAttribute(isa='list')
_poll = FieldAttribute(isa='int')
@@ -401,10 +401,10 @@ class Task(Base, Conditional, Taggable, Become):
'''
Generic logic to get the attribute or parent attribute for a task value.
'''
+
value = None
try:
value = self._attributes[attr]
-
if self._parent and (value is None or extend):
parent_value = getattr(self._parent, attr, None)
if extend:
@@ -420,23 +420,7 @@ class Task(Base, Conditional, Taggable, Become):
'''
Override for the 'tags' getattr fetcher, used from Base.
'''
- environment = self._attributes['environment']
- parent_environment = self._get_parent_attribute('environment', extend=True)
- if parent_environment is not None:
- environment = self._extend_value(environment, parent_environment)
- return environment
-
- def _get_attr_any_errors_fatal(self):
- '''
- Override for the 'tags' getattr fetcher, used from Base.
- '''
- return self._get_parent_attribute('any_errors_fatal')
-
- def _get_attr_loop(self):
- return self._attributes['loop']
-
- def _get_attr_loop_control(self):
- return self._attributes['loop_control']
+ return self._get_parent_attribute('environment', extend=True)
def get_dep_chain(self):
if self._parent: