Repository: ansible/ansible

Issue:
delegating to null crashes with AttributeError: 'NoneType' object has no attribute 'split'
##### ISSUE TYPE
- Bug Report
##### COMPONENT NAME

delegation
##### ANSIBLE VERSION

```
ansible 2.1.1.0
  config file = /home/mg/src/deployments/provisioning/ansible.cfg
  configured module search path = Default w/o overrides
```
##### CONFIGURATION

```
[defaults]
inventory = inventory
remote_user = root
vault_password_file = askpass.py
gathering = smart
fact_caching = jsonfile
fact_caching_connection = .cache/facts/
fact_caching_timeout = 86400
forks = 15
retry_files_enabled = false
```
##### OS / ENVIRONMENT

Ubuntu 16.04
##### SUMMARY

I'm pretty sure this is me doing something dumb like trying to delegate to None, but Ansible should give a clear error message and not crash.

Here's the traceback:

```
ERROR! Unexpected Exception: 'NoneType' object has no attribute 'split'
the full traceback was:

Traceback (most recent call last):
  File "/home/mg/.venv/bin/ansible-playbook", line 92, in <module>
    exit_code = cli.run()
  File "/home/mg/.venv/local/lib/python2.7/site-packages/ansible/cli/playbook.py", line 154, in run
    results = pbex.run()
  File "/home/mg/.venv/local/lib/python2.7/site-packages/ansible/executor/playbook_executor.py", line 146, in run
    result = self._tqm.run(play=play)
  File "/home/mg/.venv/local/lib/python2.7/site-packages/ansible/executor/task_queue_manager.py", line 264, in run
    play_return = strategy.run(iterator, play_context)
  File "/home/mg/.venv/local/lib/python2.7/site-packages/ansible/plugins/strategy/linear.py", line 226, in run
    task_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, host=host, task=task)
  File "/home/mg/.venv/local/lib/python2.7/site-packages/ansible/vars/__init__.py", line 371, in get_vars
    all_vars['ansible_delegated_vars'] = self._get_delegated_vars(loader, play, task, all_vars)
  File "/home/mg/.venv/local/lib/python2.7/site-packages/ansible/vars/__init__.py", line 516, in _get_delegated_vars
    include_hostvars=False,
  File "/home/mg/.venv/local/lib/python2.7/site-packages/ansible/vars/__init__.py", line 264, in get_vars
    all_vars = combine_vars(all_vars, host.get_vars())
  File "/home/mg/.venv/local/lib/python2.7/site-packages/ansible/inventory/host.py", line 132, in get_vars
    results['inventory_hostname_short'] = self.name.split('.')[0]
AttributeError: 'NoneType' object has no attribute 'split'
```

I think the task that is failing is

``` yml
- name: user for accepting pushed backups on the backup buddy
  user: name="{{ backup_user }}" state=present
  delegate_to: "{{ backup_buddy }}"
  when: backup_buddy != ""
  tags: [ backups, user ]
```

and I suspect `backup_buddy` is undefined or null.
##### STEPS TO REPRODUCE

``` yml
# test.yml

---
- hosts: localhost
  gather_facts: no
  vars:
    somewhere:
  tasks:
    - command: "true"
      delegate_to: "{{ somewhere }}"
```
##### EXPECTED RESULTS

An error like "you're trying to delegate to null".
##### ACTUAL RESULTS

```
PLAY [localhost] ***************************************************************
ERROR! Unexpected Exception: 'NoneType' object has no attribute 'split'
to see the full traceback, use -vvv
```



Discussion:
Actually, this fails as well!

``` yml
---
- hosts: localhost
  gather_facts: no
  vars:
    somewhere:
  tasks:
    - command: "true"
      delegate_to: "{{ somewhere }}"
      when: false
```

(I see I once filed bug #12722 about a very similar issue.)


Resolving patch:
diff --git a/lib/ansible/vars/__init__.py b/lib/ansible/vars/__init__.py
--- a/lib/ansible/vars/__init__.py
+++ b/lib/ansible/vars/__init__.py
@@ -458,6 +458,8 @@ def _get_delegated_vars(self, loader, play, task, existing_variables):
 
             templar.set_available_variables(vars_copy)
             delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False)
+            if not delegated_host_name:
+                raise AnsibleError(message="Undefined delegate_to host for task:", obj=task._ds)
             if delegated_host_name in delegated_host_vars:
                 # no need to repeat ourselves, as the delegate_to value
                 # does not appear to be tied to the loop item variable


Test patch: