Repository: ansible/ansible

Issue:
playbook_dir not available for include in devel branch (19606afe5f)
##### Issue Type: Bug Report
##### Ansible Version: 1.8 (devel 19606afe5f)

```
    ansible-playbook 1.8 (devel 19606afe5f) last updated 2014/11/25 08:20:50 (GMT +200)
        lib/ansible/modules/core: (detached HEAD fbc4ed7a88) last updated 2014/11/25 09:29:11 (GMT +200)
        lib/ansible/modules/extras: (detached HEAD e64751b0eb) last updated 2014/11/25 09:29:25 (GMT +200)
        v2/ansible/modules/core: (detached HEAD cb69744bce) last updated 2014/11/25 09:28:25 (GMT +200)
        v2/ansible/modules/extras: (detached HEAD 8a4f07eecd) last updated 2014/11/25 09:28:36 (GMT +200)
        configured module search path = None

```
##### Environment: Mac OS X 10.10.1 using virtualenv with Python 2.7
##### Summary:

Ansible is not be able to resolve `{{playbook_dir}}` when including a task file from another role.
##### Steps To Reproduce:

Sample at https://github.com/mfriedenhagen/ansible-no-playbookdir

Given you checked out `ansible` to `../ansible` _and_ initialized submodules please run:

```
    virtualenv -p /usr/bin/python venv
    . venv/bin/activate/
    pip install ../ansible # to get dependencies
    . ../ansible/hacking/env-setup
    ansible-playbook --version
    ansible-playbook 1.8 (devel 19606afe5f) last updated 2014/11/25 08:20:50 (GMT +200)
        lib/ansible/modules/core: (detached HEAD fbc4ed7a88) last updated 2014/11/25 09:29:11 (GMT +200)
        lib/ansible/modules/extras: (detached HEAD e64751b0eb) last updated 2014/11/25 09:29:25 (GMT +200)
        v2/ansible/modules/core: (detached HEAD cb69744bce) last updated 2014/11/25 09:28:25 (GMT +200)
        v2/ansible/modules/extras: (detached HEAD 8a4f07eecd) last updated 2014/11/25 09:28:36 (GMT +200)
        configured module search path = None
```
##### Expected Results:

Output of `ansible-playbook -i hosts -c local playbook.yml` with 1.7.2

```
    PLAY [Show playbook_dir] ****************************************************** 

    GATHERING FACTS *************************************************************** 
    ok: [127.0.0.1]

    TASK: [a | Do stuff] ********************************************************** 
    ok: [127.0.0.1] => {
        "msg": "Hallo"
    }

    TASK: [a | Do stuff in a::foo] ************************************************ 
    ok: [127.0.0.1] => {
        "playbook_dir": "/Users/mifr/workspace/foss/ansible-no-playbookdir"
    }

    TASK: [b | Do stuff in a::foo] ************************************************ 
    ok: [127.0.0.1] => {
        "playbook_dir": "/Users/mifr/workspace/foss/ansible-no-playbookdir"
    }

    TASK: [debug var=playbook_dir] ************************************************ 
    ok: [127.0.0.1] => {
        "playbook_dir": "/Users/mifr/workspace/foss/ansible-no-playbookdir"
    }

    PLAY RECAP ******************************************************************** 
    127.0.0.1                  : ok=5    changed=0    unreachable=0    failed=0   
```
##### Actual Results:

Running: `ansible-playbook -i hosts -c local playbook.yml` now ends with:

```
    ERROR: file could not read: /Users/mifr/workspace/foss/ansible-no-playbookdir/roles/b/tasks/{{playbook_dir}}/roles/a/tasks/foo.yml
``
```



Discussion:
also reported here: https://github.com/ansible/ansible/issues/9621

@abadger -- this is likely not the same issue as playbook_dir should not be at inventory scope.   It may be that it is, but it should be generally available.

Reproduced.  Looking into what could be happening.

The other issues might be intended but it looks like this is caused by the same commit.  Commit 9a0f8f0 which fixed #9498 has the problem while its parent does not.


Resolving patch:
diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py
--- a/lib/ansible/playbook/play.py
+++ b/lib/ansible/playbook/play.py
@@ -79,17 +79,21 @@ def __init__(self, playbook, ds, basedir, vault_password=None):
         elif type(self.tags) != list:
             self.tags = []
 
-        # make sure we have some special internal variables set
-        self.vars['playbook_dir'] = os.path.abspath(self.basedir)
+        # make sure we have some special internal variables set, which
+        # we use later when loading tasks and handlers
+        load_vars = dict()
+        load_vars['playbook_dir'] = os.path.abspath(self.basedir)
         if self.playbook.inventory.basedir() is not None:
-            self.vars['inventory_dir'] = self.playbook.inventory.basedir()
+            load_vars['inventory_dir'] = self.playbook.inventory.basedir()
         if self.playbook.inventory.src() is not None:
-            self.vars['inventory_file'] = self.playbook.inventory.src()
+            load_vars['inventory_file'] = self.playbook.inventory.src()
 
         # template the play vars with themselves and the extra vars
         # from the playbook, to make sure they're correct
         all_vars = utils.combine_vars(self.vars, self.playbook.extra_vars)
+        all_vars = utils.combine_vars(all_vars, load_vars)
         self.vars = template(basedir, self.vars, all_vars)
+        self.vars = utils.combine_vars(self.vars, load_vars)
 
         # We first load the vars files from the datastructure
         # so we have the default variables to pass into the roles
@@ -157,8 +161,7 @@ def __init__(self, playbook, ds, basedir, vault_password=None):
             raise errors.AnsibleError('sudo params ("sudo", "sudo_user") and su params '
                                       '("su", "su_user") cannot be used together')
 
-        load_vars = {}
-        load_vars['role_names'] = ds.get('role_names',[])
+        load_vars['role_names'] = ds.get('role_names', [])
 
         self._tasks      = self._load_tasks(self._ds.get('tasks', []), load_vars)
         self._handlers   = self._load_tasks(self._ds.get('handlers', []), load_vars)


Test patch: