diff --git a/Makefile b/Makefile
index e228c1e9f65..7702f5162da 100644
--- a/Makefile
+++ b/Makefile
@@ -94,7 +94,7 @@ tests:
PYTHONPATH=./lib $(NOSETESTS) -d -w test/units -v
newtests:
- PYTHONPATH=./v2/ $(NOSETESTS) -d -w v2/tests -v
+ PYTHONPATH=./v2 $(NOSETESTS) -d -w test/v2 -v
authors:
diff --git a/lib/ansible/modules/core b/lib/ansible/modules/core
index cb69744bcee..f624689bad2 160000
--- a/lib/ansible/modules/core
+++ b/lib/ansible/modules/core
@@ -1 +1 @@
-Subproject commit cb69744bcee4b4217d83b4a30006635ba69e2aa0
+Subproject commit f624689bad24cb3a7b2ef43d5280b5f4fbabb5bd
diff --git a/test/v2/playbook/__init__.py b/test/v2/playbook/__init__.py
new file mode 100644
index 00000000000..ec86ee61015
--- /dev/null
+++ b/test/v2/playbook/__init__.py
@@ -0,0 +1,2 @@
+# TODO: header
+
diff --git a/test/v2/playbook/task.py b/test/v2/playbook/task.py
new file mode 100644
index 00000000000..9f65a35cc5d
--- /dev/null
+++ b/test/v2/playbook/task.py
@@ -0,0 +1,37 @@
+# TODO: header
+
+from ansible.playbook.task import Task
+import unittest
+
+basic_shell_task = dict(
+ name = 'Test Task',
+ shell = 'echo hi'
+)
+
+class TestTask(unittest.TestCase):
+
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_can_construct_empty_task():
+ t = Task()
+
+ def test_can_construct_task_with_role():
+ pass
+
+ def test_can_construct_task_with_block():
+ pass
+
+ def test_can_construct_task_with_role_and_block():
+ pass
+
+ def test_can_load_simple_task():
+ t = Task.load(basic_shell_task)
+ assert t.name == basic_shell_task['name']
+ assert t.module == 'shell'
+ assert t.args == 'echo hi'
+
+
diff --git a/v2/ansible/playbook/__init__.py b/v2/ansible/playbook/__init__.py
index 6b9cfa6ce69..d2430dfc0cb 100644
--- a/v2/ansible/playbook/__init__.py
+++ b/v2/ansible/playbook/__init__.py
@@ -15,8 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see .
-import ansible.utils
-
class Playbook(object):
def __init__(self, filename):
self.ds = v2.utils.load_yaml_from_file(filename)
diff --git a/v2/ansible/playbook/base.py b/v2/ansible/playbook/base.py
index a16e22f15f7..9c2ad358c44 100644
--- a/v2/ansible/playbook/base.py
+++ b/v2/ansible/playbook/base.py
@@ -15,11 +15,23 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see .
-from errors import AnsibleError
-from playbook.tag import Tag
+#from ansible.cmmon.errors import AnsibleError
+#from playbook.tag import Tag
class Base(object):
- def __init__(self):
+ def __init__(self, attribute):
pass
+ def add_attribute(self):
+ self.attributes.push(attribute)
+
+ def load(self, data):
+ for attribute in self.attributes:
+ attribute.load(data)
+
+ def validate(self):
+ for attribute in self.attributes:
+ attribute.validate(self)
+
+
diff --git a/v2/ansible/playbook/task.py b/v2/ansible/playbook/task.py
index 9600d85b18e..4767c95106e 100644
--- a/v2/ansible/playbook/task.py
+++ b/v2/ansible/playbook/task.py
@@ -15,10 +15,11 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see .
-from playbook.base import Base
-from playbook.conditional import Conditional
-from errors import AnsibleError
-from ansible import utils
+from ansible.playbook.base import Base
+from ansible.playbook.attribute import Attribute, FieldAttribute
+from ansible.playbook.conditional import Conditional
+#from ansible.common.errors import AnsibleError
+#from ansible import utils
# TODO: it would be fantastic (if possible) if a task new where in the YAML it was defined for describing
# it in error conditions
@@ -36,81 +37,94 @@ class Task(Base):
"""
# =================================================================================
- # KEYS AND SLOTS: defines what variables in are valid in the data structure and
- # the object itself
-
- VALID_KEYS = [
- 'always_run', 'any_errors_fatal', 'async', 'connection', 'delay', 'delegate_to', 'environment',
- 'first_available_file', 'ignore_errors', 'include', 'local_action', 'meta', 'name', 'no_log',
- 'notify', 'poll', 'register', 'remote_user', 'retries', 'run_once', 'su', 'su_pass', 'su_user',
- 'sudo', 'sudo_pass', 'sudo_user', 'transport', 'until'
- ]
-
- __slots__ = [
- '_always_run', '_any_errors_fatal', '_async', '_connection', '_delay', '_delegate_to', '_environment',
- '_first_available_file', '_ignore_errors', '_include', '_local_action', '_meta', '_name', '_no_log',
- '_notify', '_poll', '_register', '_remote_user', '_retries', '_run_once', '_su', '_su_pass', '_su_user',
- '_sudo', '_sudo_pass', '_sudo_user', '_transport', '_until'
- ]
+ # ATTRIBUTES
+ # load_ and
+ # validate_
+ # will be used if defined
+ # might be possible to define others
+
+ always_run = FieldAttribute(isa='bool')
+ any_errors_fatal = FieldAttribute(isa='bool')
+ async = FieldAttribute(isa='int')
+ connection = FieldAttribute(isa='string')
+ delay = FieldAttribute(isa='int')
+ delegate_to = FieldAttribute(isa='string')
+ environment = FieldAttribute(isa='dict')
+ first_available_file = FieldAttribute(isa='list')
+ ignore_errors = FieldAttribute(isa='bool')
+
+ # FIXME: this should not be a Task
+ # include = FieldAttribute(isa='string')
+
+ local_action = FieldAttribute(isa='string', alias='action', post_validate='_set_local_action')
+
+ # FIXME: this should not be a Task
+ meta = FieldAttribute(isa='string')
+
+ name = FieldAttribute(isa='string', post_validate='_set_name')
+ no_log = FieldAttribute(isa='bool')
+ notify = FieldAttribute(isa='list')
+ poll = FieldAttribute(isa='integer')
+ register = FieldAttribute(isa='string')
+ remote_user = FieldAttribute(isa='string')
+ retries = FieldAttribute(isa='integer')
+ run_once = FieldAttribute(isa='bool')
+ su = FieldAttribute(isa='bool')
+ su_pass = FieldAttribute(isa='string')
+ su_user = FieldAttribute(isa='string')
+ sudo = FieldAttribute(isa='bool')
+ sudo_user = FieldAttribute(isa='string')
+ sudo_pass = FieldAttribute(isa='string')
+ transport = FieldAttribute(isa='string')
+ until = FieldAttribute(isa='list') # ?
+
+ role = Attribute()
+ block = Attribute()
# ==================================================================================
def __init__(self, block=None, role=None):
''' constructors a task, without the Task.load classmethod, it will be pretty blank '''
- self._block = block
- self._role = role
- self._reset()
+ self.block = block
+ self.role = role
super(Task, self).__init__()
- # TODO: move to BaseObject
- def _reset(self):
- ''' clear out the object '''
-
- for x in __slots__:
- setattr(x, None)
-
# ==================================================================================
# BASIC ACCESSORS
def get_name(self):
''' return the name of the task '''
if self._role:
- return "%s : %s" % (self._role.get_name(), self._name)
- else:
- return self._name
+ return "%s : %s" % (self._role.get_name(), self._name)
+ else:
+ return self._name
def __repr__(self):
''' returns a human readable representation of the task '''
return "TASK: %s" % self.get_name()
- # FIXME: does a task have variables?
- def get_vars(self):
- ''' return the variables associated with the task '''
- raise exception.NotImplementedError()
-
- def get_role(self):
- ''' return the role associated with the task '''
- return self._role
+ @classmethod
+ def load(self, block=None, role=None, data=None):
+ self = Task(block=block, role=role)
+ self._load_field_attributes(data) # from BaseObject
+ self._load_plugin_attributes(data) # from here, becuase of lookupPlugins
+ return self
- def get_block(self):
- ''' return the block the task is in '''
- return self._block
+ def _load_plugin_attributes(self, data):
+ module_names = self._module_names()
+ for (k,v) in data.iteritems():
+ if k in module_names:
+ self.module = k
+ self.args = v
# ==================================================================================
- # LOAD: functions related to walking the datastructure and storing data
+ # BELOW THIS LINE
+ # info below this line is "old" and is before the attempt to build Attributes
+ # use as reference but plan to replace and radically simplify
+ # ==================================================================================
- def _load_parameters(data):
- ''' validate/transmogrify/assign any module parameters for this task '''
-
- if isinstance(data, dict):
- return dict(_parameters=data)
- elif isinstance(data, basestring):
- return dict(_parameters=utils.parse_kv(data))
- elif isinstance(data, None):
- return dict(_parameters='')
- else:
- raise AnsibleError("invalid arguments specified, got '%s' (type=%s')" % (data, type(data)))
+LEGACY = """
def _load_action(self, ds, k, v):
''' validate/transmogrify/assign the module and parameters if used in 'action/local_action' format '''
@@ -301,3 +315,5 @@ class Task(Base):
if self._first_available_file and self._lookup_plugin:
raise AnsibleError("with_(plugin), and first_available_file are mutually incompatible in a single task")
+"""
+
diff --git a/v2/ansible/runner/__init__.py b/v2/ansible/runner/__init__.py
index ebebb9cfc01..b8cc0a9219a 100644
--- a/v2/ansible/runner/__init__.py
+++ b/v2/ansible/runner/__init__.py
@@ -15,8 +15,8 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see .
-from v2.inventory import Host
-from v2.playbook import Task
+#from v2.inventory import Host
+#from v2.playbook import Task
class Runner(object):
pass