Repository: ansible/ansible

Issue:
local_action being run on target host instead of local machine
Issue Type:  Bug Report

Ansible Version: 
ansible 2.0.0 (devel 86100da3a0) last updated 2015/08/18 13:23:59 (GMT -700)
  lib/ansible/modules/core: (detached HEAD dea5f5d15e) last updated 2015/08/18 13:23:11 (GMT -700)
  lib/ansible/modules/extras: (detached HEAD 210ee3febc) last updated 2015/08/18 13:23:11 (GMT -700)
  v1/ansible/modules/core: (detached HEAD f8d8af17cd) last updated 2015/08/18 13:23:11 (GMT -700)
  v1/ansible/modules/extras: (detached HEAD 495ad450e5) last updated 2015/08/18 13:23:11 (GMT -700)

Ansible Configuration:

We define remote_user to be root
and transport to be ssh

Environment:  Centos 6.7

Summary:

When running 
from ansible 2.0.0. (devel 464a436f8f)
local_actions run on the local machine as they should

When running from:
ansible 2.0.0 (devel 86100da3a0) last updated 2015/08/18 13:23:59 (GMT -700)
  lib/ansible/modules/core: (detached HEAD dea5f5d15e) last updated 2015/08/18 13:23:11 (GMT -700)
  lib/ansible/modules/extras: (detached HEAD 210ee3febc) last updated 2015/08/18 13:23:11 (GMT -700)
  v1/ansible/modules/core: (detached HEAD f8d8af17cd) last updated 2015/08/18 13:23:11 (GMT -700)
  v1/ansible/modules/extras: (detached HEAD 495ad450e5) last updated 2015/08/18 13:23:11 (GMT -700)
They run on the inventory host machine even thought it is a local_action

Steps To Reproduce:

Run playbook

```

---

- hosts: sample-host
  tasks:
    - name: testing localaction
      local_action: shell hostname
      register: testingoutput
    - debug: var=testingoutput
```

Expected Results:
ansible 2.0.0. (devel 464a436f8f)

```
TASK [testing localaction] *****************************************************
changed: [sample-host] => {"changed": true, "cmd": "hostname", "delta": "0:00:00.002314", "end": "2015-08-18 13:59:34.326815", "rc": 0, "start": "2015-08-18 13:59:34.324501", "stderr": "", "stdout": "ansible-server.sample", "stdout_lines": ["ansible-server.sample"], "warnings": []}

TASK [debug var=testingoutput] *************************************************
ok: [sample-host] => {
    "changed": false, 
    "testingoutput": {
        "changed": true, 
        "cmd": "hostname", 
        "delta": "0:00:00.002314", 
        "end": "2015-08-18 13:59:34.326815", 
        "rc": 0, 
        "start": "2015-08-18 13:59:34.324501", 
        "stderr": "", 
        "stdout": "ansible-server.sample", 
        "stdout_lines": [
            "ansible-server.sample"
        ], 
        "warnings": []
    }
}
```

Actual Results:
ansible 2.0.0 (devel 86100da3a0)

```
TASK [testing localaction] *****************************************************
changed: [sample-host] => {"changed": true, "cmd": "hostname", "delta": "0:00:00.003015", "end": "2015-08-18 13:55:46.846948", "rc": 0, "start": "2015-08-18 13:55:46.843933", "stderr": "", "stdout": "sample-host.sample", "stdout_lines": ["sample-host.sample"], "warnings": []}

TASK [debug var=testingoutput] *************************************************
ok: [sample-host] => {
    "changed": false, 
    "testingoutput": {
        "changed": true, 
        "cmd": "hostname", 
        "delta": "0:00:00.003015", 
        "end": "2015-08-18 13:55:46.846948", 
        "rc": 0, 
        "start": "2015-08-18 13:55:46.843933", 
        "stderr": "", 
        "stdout": "sample-host.sample", 
        "stdout_lines": [
            "sample-host.sample"
        ], 
        "warnings": []
    }
}
```

local_action being run on target host instead of local machine
Issue Type:  Bug Report

Ansible Version: 
ansible 2.0.0 (devel 86100da3a0) last updated 2015/08/18 13:23:59 (GMT -700)
  lib/ansible/modules/core: (detached HEAD dea5f5d15e) last updated 2015/08/18 13:23:11 (GMT -700)
  lib/ansible/modules/extras: (detached HEAD 210ee3febc) last updated 2015/08/18 13:23:11 (GMT -700)
  v1/ansible/modules/core: (detached HEAD f8d8af17cd) last updated 2015/08/18 13:23:11 (GMT -700)
  v1/ansible/modules/extras: (detached HEAD 495ad450e5) last updated 2015/08/18 13:23:11 (GMT -700)

Ansible Configuration:

We define remote_user to be root
and transport to be ssh

Environment:  Centos 6.7

Summary:

When running 
from ansible 2.0.0. (devel 464a436f8f)
local_actions run on the local machine as they should

When running from:
ansible 2.0.0 (devel 86100da3a0) last updated 2015/08/18 13:23:59 (GMT -700)
  lib/ansible/modules/core: (detached HEAD dea5f5d15e) last updated 2015/08/18 13:23:11 (GMT -700)
  lib/ansible/modules/extras: (detached HEAD 210ee3febc) last updated 2015/08/18 13:23:11 (GMT -700)
  v1/ansible/modules/core: (detached HEAD f8d8af17cd) last updated 2015/08/18 13:23:11 (GMT -700)
  v1/ansible/modules/extras: (detached HEAD 495ad450e5) last updated 2015/08/18 13:23:11 (GMT -700)
They run on the inventory host machine even thought it is a local_action

Steps To Reproduce:

Run playbook

```

---

- hosts: sample-host
  tasks:
    - name: testing localaction
      local_action: shell hostname
      register: testingoutput
    - debug: var=testingoutput
```

Expected Results:
ansible 2.0.0. (devel 464a436f8f)

```
TASK [testing localaction] *****************************************************
changed: [sample-host] => {"changed": true, "cmd": "hostname", "delta": "0:00:00.002314", "end": "2015-08-18 13:59:34.326815", "rc": 0, "start": "2015-08-18 13:59:34.324501", "stderr": "", "stdout": "ansible-server.sample", "stdout_lines": ["ansible-server.sample"], "warnings": []}

TASK [debug var=testingoutput] *************************************************
ok: [sample-host] => {
    "changed": false, 
    "testingoutput": {
        "changed": true, 
        "cmd": "hostname", 
        "delta": "0:00:00.002314", 
        "end": "2015-08-18 13:59:34.326815", 
        "rc": 0, 
        "start": "2015-08-18 13:59:34.324501", 
        "stderr": "", 
        "stdout": "ansible-server.sample", 
        "stdout_lines": [
            "ansible-server.sample"
        ], 
        "warnings": []
    }
}
```

Actual Results:
ansible 2.0.0 (devel 86100da3a0)

```
TASK [testing localaction] *****************************************************
changed: [sample-host] => {"changed": true, "cmd": "hostname", "delta": "0:00:00.003015", "end": "2015-08-18 13:55:46.846948", "rc": 0, "start": "2015-08-18 13:55:46.843933", "stderr": "", "stdout": "sample-host.sample", "stdout_lines": ["sample-host.sample"], "warnings": []}

TASK [debug var=testingoutput] *************************************************
ok: [sample-host] => {
    "changed": false, 
    "testingoutput": {
        "changed": true, 
        "cmd": "hostname", 
        "delta": "0:00:00.003015", 
        "end": "2015-08-18 13:55:46.846948", 
        "rc": 0, 
        "start": "2015-08-18 13:55:46.843933", 
        "stderr": "", 
        "stdout": "sample-host.sample", 
        "stdout_lines": [
            "sample-host.sample"
        ], 
        "warnings": []
    }
}
```



Discussion:
confirmed the issue, as a workaround connection: local still works as it should

so local_action is an alias to delegate_to: localhost, which seems to also not be working

confirmed the issue, as a workaround connection: local still works as it should

so local_action is an alias to delegate_to: localhost, which seems to also not be working


Resolving patch:
diff --git a/lib/ansible/parsing/mod_args.py b/lib/ansible/parsing/mod_args.py
--- a/lib/ansible/parsing/mod_args.py
+++ b/lib/ansible/parsing/mod_args.py
@@ -234,10 +234,9 @@ def parse(self):
         task, dealing with all sorts of levels of fuzziness.
         '''
 
-        thing      = None
-
+        thing       = None
         action      = None
-        delegate_to = self._task_ds.get('delegate_to', None)
+        connection  = self._task_ds.get('connection', None)
         args        = dict()
 
 
@@ -256,11 +255,11 @@ def parse(self):
 
         # local_action
         if 'local_action' in self._task_ds:
-            # local_action is similar but also implies a delegate_to
+            # local_action is similar but also implies a connection='local'
             if action is not None:
                 raise AnsibleParserError("action and local_action are mutually exclusive", obj=self._task_ds)
             thing = self._task_ds.get('local_action', '')
-            delegate_to = 'localhost'
+            connection = 'local'
             action, args = self._normalize_parameters(thing, additional_args=additional_args)
 
         # module: <stuff> is the more new-style invocation
@@ -289,4 +288,4 @@ def parse(self):
         # shell modules require special handling
         (action, args) = self._handle_shell_weirdness(action, args)
 
-        return (action, args, delegate_to)
+        return (action, args, connection)
diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py
--- a/lib/ansible/playbook/task.py
+++ b/lib/ansible/playbook/task.py
@@ -157,11 +157,11 @@ def preprocess_data(self, ds):
         # and the delegate_to value from the various possible forms
         # supported as legacy
         args_parser = ModuleArgsParser(task_ds=ds)
-        (action, args, delegate_to) = args_parser.parse()
+        (action, args, connection) = args_parser.parse()
 
         new_ds['action']      = action
         new_ds['args']        = args
-        new_ds['delegate_to'] = delegate_to
+        new_ds['connection'] = connection
 
         # we handle any 'vars' specified in the ds here, as we may
         # be adding things to them below (special handling for includes).
@@ -174,7 +174,7 @@ def preprocess_data(self, ds):
             new_ds['vars'] = dict()
 
         for (k,v) in ds.iteritems():
-            if k in ('action', 'local_action', 'args', 'delegate_to') or k == action or k == 'shell':
+            if k in ('action', 'local_action', 'args', 'connection') or k == action or k == 'shell':
                 # we don't want to re-assign these values, which were
                 # determined by the ModuleArgsParser() above
                 continue


Test patch:
diff --git a/test/units/parsing/test_mod_args.py b/test/units/parsing/test_mod_args.py
--- a/test/units/parsing/test_mod_args.py
+++ b/test/units/parsing/test_mod_args.py
@@ -109,11 +109,11 @@ def test_action_with_complex_and_complex_args(self):
 
     def test_local_action_string(self):
         m = ModuleArgsParser(dict(local_action='copy src=a dest=b'))
-        mod, args, to = m.parse()
-        self._debug(mod, args, to)
+        mod, args, connection = m.parse()
+        self._debug(mod, args, connection)
         self.assertEqual(mod, 'copy')
         self.assertEqual(args, dict(src='a', dest='b'))
-        self.assertIs(to, 'localhost')
+        self.assertIs(connection, 'local')
 
     def test_multiple_actions(self):
         m = ModuleArgsParser(dict(action='shell echo hi', local_action='shell echo hi'))