We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
BUG: "'FabricRemoteAction' object has no attribute 'id'"
Fabric based actions are failing due to an incorrectly named attribute.

root@st2stage201:/tmp# st2 execution get 5493450cce36d2111eb26c79
STATUS: failed
RESULT: 
{
    "message": "'FabricRemoteAction' object has no attribute 'id'", 
    "traceback": "  File "/usr/lib/python2.7/dist-packages/st2actions/container/base.py", line 117, in _do_run
    run_result = runner.run(action_params)
  File "/usr/lib/python2.7/dist-packages/st2actions/runners/fabricrunner.py", line 106, in run
    result = self._run(remote_action)
  File "/usr/lib/python2.7/dist-packages/st2actions/runners/fabricrunner.py", line 120, in _run
    remote_action.name, remote_action.id, remote_action.get_command(),
"
}


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `st2actions/st2actions/runners/fabricrunner.py`
Content:
```
1 # Licensed to the StackStorm, Inc ('StackStorm') under one or more
2 # contributor license agreements.  See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License.  You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 import os
17 import uuid
18 
19 from fabric.api import (env, execute)
20 from oslo.config import cfg
21 import six
22 
23 from st2actions.runners import ActionRunner
24 from st2actions.runners import ShellRunnerMixin
25 from st2common import log as logging
26 from st2common.exceptions.actionrunner import ActionRunnerPreRunError
27 from st2common.exceptions.fabricrunner import FabricExecutionFailureException
28 from st2common.constants.action import ACTIONEXEC_STATUS_SUCCEEDED, ACTIONEXEC_STATUS_FAILED
29 from st2common.models.system.action import (FabricRemoteAction, FabricRemoteScriptAction)
30 
31 # Replace with container call to get logger.
32 LOG = logging.getLogger(__name__)
33 
34 DEFAULT_ACTION_TIMEOUT = 60
35 
36 
37 # Fabric environment level settings.
38 # XXX: Note fabric env is a global singleton.
39 env.parallel = True  # By default, execute things in parallel. Uses multiprocessing under the hood.
40 env.user = cfg.CONF.system_user.user
41 ssh_key_file = cfg.CONF.system_user.ssh_key_file
42 
43 if ssh_key_file:
44     ssh_key_file = os.path.expanduser(ssh_key_file)
45 
46 if ssh_key_file and os.path.exists(ssh_key_file):
47     env.key_filename = ssh_key_file
48 
49 env.timeout = 10  # Timeout for connections (in seconds)
50 env.command_timeout = DEFAULT_ACTION_TIMEOUT  # timeout for commands (in seconds)
51 env.combine_stderr = False
52 env.group = 'staff'
53 env.abort_exception = FabricExecutionFailureException
54 
55 # constants to lookup in runner_parameters.
56 RUNNER_HOSTS = 'hosts'
57 RUNNER_PARALLEL = 'parallel'
58 RUNNER_SUDO = 'sudo'
59 RUNNER_ON_BEHALF_USER = 'user'
60 RUNNER_REMOTE_DIR = 'dir'
61 RUNNER_COMMAND = 'cmd'
62 RUNNER_KWARG_OP = 'kwarg_op'
63 RUNNER_TIMEOUT = 'timeout'
64 
65 
66 def get_runner():
67     return FabricRunner(str(uuid.uuid4()))
68 
69 
70 class FabricRunner(ActionRunner, ShellRunnerMixin):
71     def __init__(self, runner_id):
72         super(FabricRunner, self).__init__(runner_id=runner_id)
73         self._hosts = None
74         self._parallel = True
75         self._sudo = False
76         self._on_behalf_user = None
77         self._user = None
78         self._kwarg_op = '--'
79 
80     def pre_run(self):
81         LOG.debug('Entering FabricRunner.pre_run() for actionexec_id="%s"',
82                   self.action_execution_id)
83         LOG.debug('    runner_parameters = %s', self.runner_parameters)
84         hosts = self.runner_parameters.get(RUNNER_HOSTS, '').split(',')
85         self._hosts = [h.strip() for h in hosts if len(h) > 0]
86         if len(self._hosts) < 1:
87             raise ActionRunnerPreRunError('No hosts specified to run action for action %s.',
88                                           self.action_execution_id)
89         self._parallel = self.runner_parameters.get(RUNNER_PARALLEL, True)
90         self._sudo = self.runner_parameters.get(RUNNER_SUDO, False)
91         self._sudo = self._sudo if self._sudo else False
92         self._on_behalf_user = self.context.get(RUNNER_ON_BEHALF_USER, env.user)
93         self._user = cfg.CONF.system_user.user
94         self._kwarg_op = self.runner_parameters.get(RUNNER_KWARG_OP, '--')
95         self._timeout = self.runner_parameters.get(RUNNER_TIMEOUT, DEFAULT_ACTION_TIMEOUT)
96 
97         LOG.info('[FabricRunner="%s", actionexec_id="%s"] Finished pre_run.',
98                  self.runner_id, self.action_execution_id)
99 
100     def run(self, action_parameters):
101         LOG.debug('    action_parameters = %s', action_parameters)
102         remote_action = self._get_fabric_remote_action(action_parameters) \
103             if self.entry_point is None or len(self.entry_point) < 1 \
104             else self._get_fabric_remote_script_action(action_parameters)
105         LOG.debug('Will execute remote_action : %s.', str(remote_action))
106         result = self._run(remote_action)
107         LOG.debug('Executed remote_action : %s. Result is : %s.', remote_action, result)
108         self.container_service.report_status(FabricRunner._get_result_status(
109             result, cfg.CONF.ssh_runner.allow_partial_failure))
110         self.container_service.report_result(result)
111 
112         # TODO (manas) : figure out the right boolean representation.
113         return result is not None
114 
115     def _run(self, remote_action):
116         LOG.info('Executing action via FabricRunner :%s for user: %s.',
117                  self.runner_id, remote_action.get_on_behalf_user())
118         LOG.info(('[Action info] name: %s, Id: %s, command: %s, on behalf user: %s, '
119                   'actual user: %s, sudo: %s'),
120                  remote_action.name, remote_action.id, remote_action.get_command(),
121                  remote_action.get_on_behalf_user(), remote_action.get_user(),
122                  remote_action.is_sudo())
123         results = execute(remote_action.get_fabric_task(), hosts=remote_action.hosts)
124         return results
125 
126     def _get_fabric_remote_action(self, action_paramaters):
127         command = self.runner_parameters.get(RUNNER_COMMAND, None)
128         env_vars = self._get_env_vars()
129         return FabricRemoteAction(self.action_name,
130                                   str(self.action_execution_id),
131                                   command,
132                                   env_vars=env_vars,
133                                   on_behalf_user=self._on_behalf_user,
134                                   user=self._user,
135                                   hosts=self._hosts,
136                                   parallel=self._parallel,
137                                   sudo=self._sudo,
138                                   timeout=self._timeout)
139 
140     def _get_fabric_remote_script_action(self, action_parameters):
141         script_local_path_abs = self.entry_point
142         pos_args, named_args = self._get_script_args(action_parameters)
143         named_args = self._transform_named_args(named_args)
144         env_vars = self._get_env_vars()
145         remote_dir = self.runner_parameters.get(RUNNER_REMOTE_DIR,
146                                                 cfg.CONF.ssh_runner.remote_dir)
147         remote_dir = os.path.join(remote_dir, self.action_execution_id)
148         return FabricRemoteScriptAction(self.action_name,
149                                         str(self.action_execution_id),
150                                         script_local_path_abs,
151                                         self.libs_dir_path,
152                                         named_args=named_args,
153                                         positional_args=pos_args,
154                                         env_vars=env_vars,
155                                         on_behalf_user=self._on_behalf_user,
156                                         user=self._user,
157                                         remote_dir=remote_dir,
158                                         hosts=self._hosts,
159                                         parallel=self._parallel,
160                                         sudo=self._sudo,
161                                         timeout=self._timeout)
162 
163     def _get_env_vars(self):
164         return {'st2_auth_token': self.auth_token.token} if self.auth_token else {}
165 
166     @staticmethod
167     def _get_result_status(result, allow_partial_failure):
168         success = not allow_partial_failure
169         for r in six.itervalues(result):
170             if allow_partial_failure:
171                 success |= r.get('succeeded', False)
172                 if success:
173                     return ACTIONEXEC_STATUS_SUCCEEDED
174             else:
175                 success &= r.get('succeeded', False)
176                 if not success:
177                     return ACTIONEXEC_STATUS_FAILED
178         return ACTIONEXEC_STATUS_SUCCEEDED if success else ACTIONEXEC_STATUS_FAILED
179 
180 
181 # XXX: Write proper tests.
182 if __name__ == '__main__':
183 
184     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
185     print('!!!!!!!!!!!!!!!!!!!!! NORMAL CMD !!!!!!!!!!!!!!!!!!!!!!!!!!')
186     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
187     runner = FabricRunner(str(uuid.uuid4()))
188     remote_action = FabricRemoteAction('UNAME', 'action_exec_id' + str(uuid.uuid4()), 'uname -a',
189                                        'narcissist', 'stanley', hosts=['54.191.85.86',
190                                        '54.191.17.38', '54.200.102.55'])
191     print(str(remote_action))
192     results = runner._run(remote_action)
193 
194     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
195     print('!!!!!!!!!!!!!!!!!!!!! RESULTS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
196     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
197 
198     print(results)
199 
200     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
201     print('!!!!!!!!!!!!!!!!!!!!! SUDO CMD !!!!!!!!!!!!!!!!!!!!!!!!!!')
202     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
203     runner = FabricRunner(str(uuid.uuid4()))
204     remote_action = FabricRemoteAction('UNAME', 'action_exec_id' + str(uuid.uuid4()), 'uname -a',
205                                        'narcissist', 'stanley', hosts=['54.191.85.86',
206                                        '54.191.17.38', '54.200.102.55'], parallel=True, sudo=True)
207     results = runner._run(remote_action)
208 
209     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
210     print('!!!!!!!!!!!!!!!!!!!!! RESULTS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
211     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
212 
213     print(results)
214 
215     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
216     print('!!!!!!!!!!!!!!!!!!!!! SCRIPT DAWG !!!!!!!!!!!!!!!!!!!!!!!!!!!')
217     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
218     script_action = FabricRemoteScriptAction('UNAME', 'action_exec_id' + str(uuid.uuid4()),
219                                              '/tmp/ls-script.sh', named_args={},
220                                              positional_args='/tmp', on_behalf_user='narcissist',
221                                              user='stanley', hosts=['54.191.85.86'],
222                                              parallel=True, sudo=False)
223     results = runner._run(script_action)
224 
225     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
226     print('!!!!!!!!!!!!!!!!!!!!! RESULTS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
227     print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
228 
229     print(results)
230
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/st2actions/st2actions/runners/fabricrunner.py b/st2actions/st2actions/runners/fabricrunner.py
--- a/st2actions/st2actions/runners/fabricrunner.py
+++ b/st2actions/st2actions/runners/fabricrunner.py
@@ -117,7 +117,7 @@
                  self.runner_id, remote_action.get_on_behalf_user())
         LOG.info(('[Action info] name: %s, Id: %s, command: %s, on behalf user: %s, '
                   'actual user: %s, sudo: %s'),
-                 remote_action.name, remote_action.id, remote_action.get_command(),
+                 remote_action.name, remote_action.action_exec_id, remote_action.get_command(),
                  remote_action.get_on_behalf_user(), remote_action.get_user(),
                  remote_action.is_sudo())
         results = execute(remote_action.get_fabric_task(), hosts=remote_action.hosts)

{"golden_diff": "diff --git a/st2actions/st2actions/runners/fabricrunner.py b/st2actions/st2actions/runners/fabricrunner.py\n--- a/st2actions/st2actions/runners/fabricrunner.py\n+++ b/st2actions/st2actions/runners/fabricrunner.py\n@@ -117,7 +117,7 @@\n                  self.runner_id, remote_action.get_on_behalf_user())\n         LOG.info(('[Action info] name: %s, Id: %s, command: %s, on behalf user: %s, '\n                   'actual user: %s, sudo: %s'),\n-                 remote_action.name, remote_action.id, remote_action.get_command(),\n+                 remote_action.name, remote_action.action_exec_id, remote_action.get_command(),\n                  remote_action.get_on_behalf_user(), remote_action.get_user(),\n                  remote_action.is_sudo())\n         results = execute(remote_action.get_fabric_task(), hosts=remote_action.hosts)\n", "issue": "BUG: \"'FabricRemoteAction' object has no attribute 'id'\"\nFabric based actions are failing due to an incorrectly named attribute.\n\nroot@st2stage201:/tmp# st2 execution get 5493450cce36d2111eb26c79\nSTATUS: failed\nRESULT: \n{\n    \"message\": \"'FabricRemoteAction' object has no attribute 'id'\", \n    \"traceback\": \"  File \"/usr/lib/python2.7/dist-packages/st2actions/container/base.py\", line 117, in _do_run\n    run_result = runner.run(action_params)\n  File \"/usr/lib/python2.7/dist-packages/st2actions/runners/fabricrunner.py\", line 106, in run\n    result = self._run(remote_action)\n  File \"/usr/lib/python2.7/dist-packages/st2actions/runners/fabricrunner.py\", line 120, in _run\n    remote_action.name, remote_action.id, remote_action.get_command(),\n\"\n}\n\n", "before_files": [{"content": "# Licensed to the StackStorm, Inc ('StackStorm') under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport uuid\n\nfrom fabric.api import (env, execute)\nfrom oslo.config import cfg\nimport six\n\nfrom st2actions.runners import ActionRunner\nfrom st2actions.runners import ShellRunnerMixin\nfrom st2common import log as logging\nfrom st2common.exceptions.actionrunner import ActionRunnerPreRunError\nfrom st2common.exceptions.fabricrunner import FabricExecutionFailureException\nfrom st2common.constants.action import ACTIONEXEC_STATUS_SUCCEEDED, ACTIONEXEC_STATUS_FAILED\nfrom st2common.models.system.action import (FabricRemoteAction, FabricRemoteScriptAction)\n\n# Replace with container call to get logger.\nLOG = logging.getLogger(__name__)\n\nDEFAULT_ACTION_TIMEOUT = 60\n\n\n# Fabric environment level settings.\n# XXX: Note fabric env is a global singleton.\nenv.parallel = True  # By default, execute things in parallel. Uses multiprocessing under the hood.\nenv.user = cfg.CONF.system_user.user\nssh_key_file = cfg.CONF.system_user.ssh_key_file\n\nif ssh_key_file:\n    ssh_key_file = os.path.expanduser(ssh_key_file)\n\nif ssh_key_file and os.path.exists(ssh_key_file):\n    env.key_filename = ssh_key_file\n\nenv.timeout = 10  # Timeout for connections (in seconds)\nenv.command_timeout = DEFAULT_ACTION_TIMEOUT  # timeout for commands (in seconds)\nenv.combine_stderr = False\nenv.group = 'staff'\nenv.abort_exception = FabricExecutionFailureException\n\n# constants to lookup in runner_parameters.\nRUNNER_HOSTS = 'hosts'\nRUNNER_PARALLEL = 'parallel'\nRUNNER_SUDO = 'sudo'\nRUNNER_ON_BEHALF_USER = 'user'\nRUNNER_REMOTE_DIR = 'dir'\nRUNNER_COMMAND = 'cmd'\nRUNNER_KWARG_OP = 'kwarg_op'\nRUNNER_TIMEOUT = 'timeout'\n\n\ndef get_runner():\n    return FabricRunner(str(uuid.uuid4()))\n\n\nclass FabricRunner(ActionRunner, ShellRunnerMixin):\n    def __init__(self, runner_id):\n        super(FabricRunner, self).__init__(runner_id=runner_id)\n        self._hosts = None\n        self._parallel = True\n        self._sudo = False\n        self._on_behalf_user = None\n        self._user = None\n        self._kwarg_op = '--'\n\n    def pre_run(self):\n        LOG.debug('Entering FabricRunner.pre_run() for actionexec_id=\"%s\"',\n                  self.action_execution_id)\n        LOG.debug('    runner_parameters = %s', self.runner_parameters)\n        hosts = self.runner_parameters.get(RUNNER_HOSTS, '').split(',')\n        self._hosts = [h.strip() for h in hosts if len(h) > 0]\n        if len(self._hosts) < 1:\n            raise ActionRunnerPreRunError('No hosts specified to run action for action %s.',\n                                          self.action_execution_id)\n        self._parallel = self.runner_parameters.get(RUNNER_PARALLEL, True)\n        self._sudo = self.runner_parameters.get(RUNNER_SUDO, False)\n        self._sudo = self._sudo if self._sudo else False\n        self._on_behalf_user = self.context.get(RUNNER_ON_BEHALF_USER, env.user)\n        self._user = cfg.CONF.system_user.user\n        self._kwarg_op = self.runner_parameters.get(RUNNER_KWARG_OP, '--')\n        self._timeout = self.runner_parameters.get(RUNNER_TIMEOUT, DEFAULT_ACTION_TIMEOUT)\n\n        LOG.info('[FabricRunner=\"%s\", actionexec_id=\"%s\"] Finished pre_run.',\n                 self.runner_id, self.action_execution_id)\n\n    def run(self, action_parameters):\n        LOG.debug('    action_parameters = %s', action_parameters)\n        remote_action = self._get_fabric_remote_action(action_parameters) \\\n            if self.entry_point is None or len(self.entry_point) < 1 \\\n            else self._get_fabric_remote_script_action(action_parameters)\n        LOG.debug('Will execute remote_action : %s.', str(remote_action))\n        result = self._run(remote_action)\n        LOG.debug('Executed remote_action : %s. Result is : %s.', remote_action, result)\n        self.container_service.report_status(FabricRunner._get_result_status(\n            result, cfg.CONF.ssh_runner.allow_partial_failure))\n        self.container_service.report_result(result)\n\n        # TODO (manas) : figure out the right boolean representation.\n        return result is not None\n\n    def _run(self, remote_action):\n        LOG.info('Executing action via FabricRunner :%s for user: %s.',\n                 self.runner_id, remote_action.get_on_behalf_user())\n        LOG.info(('[Action info] name: %s, Id: %s, command: %s, on behalf user: %s, '\n                  'actual user: %s, sudo: %s'),\n                 remote_action.name, remote_action.id, remote_action.get_command(),\n                 remote_action.get_on_behalf_user(), remote_action.get_user(),\n                 remote_action.is_sudo())\n        results = execute(remote_action.get_fabric_task(), hosts=remote_action.hosts)\n        return results\n\n    def _get_fabric_remote_action(self, action_paramaters):\n        command = self.runner_parameters.get(RUNNER_COMMAND, None)\n        env_vars = self._get_env_vars()\n        return FabricRemoteAction(self.action_name,\n                                  str(self.action_execution_id),\n                                  command,\n                                  env_vars=env_vars,\n                                  on_behalf_user=self._on_behalf_user,\n                                  user=self._user,\n                                  hosts=self._hosts,\n                                  parallel=self._parallel,\n                                  sudo=self._sudo,\n                                  timeout=self._timeout)\n\n    def _get_fabric_remote_script_action(self, action_parameters):\n        script_local_path_abs = self.entry_point\n        pos_args, named_args = self._get_script_args(action_parameters)\n        named_args = self._transform_named_args(named_args)\n        env_vars = self._get_env_vars()\n        remote_dir = self.runner_parameters.get(RUNNER_REMOTE_DIR,\n                                                cfg.CONF.ssh_runner.remote_dir)\n        remote_dir = os.path.join(remote_dir, self.action_execution_id)\n        return FabricRemoteScriptAction(self.action_name,\n                                        str(self.action_execution_id),\n                                        script_local_path_abs,\n                                        self.libs_dir_path,\n                                        named_args=named_args,\n                                        positional_args=pos_args,\n                                        env_vars=env_vars,\n                                        on_behalf_user=self._on_behalf_user,\n                                        user=self._user,\n                                        remote_dir=remote_dir,\n                                        hosts=self._hosts,\n                                        parallel=self._parallel,\n                                        sudo=self._sudo,\n                                        timeout=self._timeout)\n\n    def _get_env_vars(self):\n        return {'st2_auth_token': self.auth_token.token} if self.auth_token else {}\n\n    @staticmethod\n    def _get_result_status(result, allow_partial_failure):\n        success = not allow_partial_failure\n        for r in six.itervalues(result):\n            if allow_partial_failure:\n                success |= r.get('succeeded', False)\n                if success:\n                    return ACTIONEXEC_STATUS_SUCCEEDED\n            else:\n                success &= r.get('succeeded', False)\n                if not success:\n                    return ACTIONEXEC_STATUS_FAILED\n        return ACTIONEXEC_STATUS_SUCCEEDED if success else ACTIONEXEC_STATUS_FAILED\n\n\n# XXX: Write proper tests.\nif __name__ == '__main__':\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! NORMAL CMD !!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    runner = FabricRunner(str(uuid.uuid4()))\n    remote_action = FabricRemoteAction('UNAME', 'action_exec_id' + str(uuid.uuid4()), 'uname -a',\n                                       'narcissist', 'stanley', hosts=['54.191.85.86',\n                                       '54.191.17.38', '54.200.102.55'])\n    print(str(remote_action))\n    results = runner._run(remote_action)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! RESULTS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n\n    print(results)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! SUDO CMD !!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    runner = FabricRunner(str(uuid.uuid4()))\n    remote_action = FabricRemoteAction('UNAME', 'action_exec_id' + str(uuid.uuid4()), 'uname -a',\n                                       'narcissist', 'stanley', hosts=['54.191.85.86',\n                                       '54.191.17.38', '54.200.102.55'], parallel=True, sudo=True)\n    results = runner._run(remote_action)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! RESULTS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n\n    print(results)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! SCRIPT DAWG !!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    script_action = FabricRemoteScriptAction('UNAME', 'action_exec_id' + str(uuid.uuid4()),\n                                             '/tmp/ls-script.sh', named_args={},\n                                             positional_args='/tmp', on_behalf_user='narcissist',\n                                             user='stanley', hosts=['54.191.85.86'],\n                                             parallel=True, sudo=False)\n    results = runner._run(script_action)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! RESULTS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n\n    print(results)\n", "path": "st2actions/st2actions/runners/fabricrunner.py"}], "after_files": [{"content": "# Licensed to the StackStorm, Inc ('StackStorm') under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport uuid\n\nfrom fabric.api import (env, execute)\nfrom oslo.config import cfg\nimport six\n\nfrom st2actions.runners import ActionRunner\nfrom st2actions.runners import ShellRunnerMixin\nfrom st2common import log as logging\nfrom st2common.exceptions.actionrunner import ActionRunnerPreRunError\nfrom st2common.exceptions.fabricrunner import FabricExecutionFailureException\nfrom st2common.constants.action import ACTIONEXEC_STATUS_SUCCEEDED, ACTIONEXEC_STATUS_FAILED\nfrom st2common.models.system.action import (FabricRemoteAction, FabricRemoteScriptAction)\n\n# Replace with container call to get logger.\nLOG = logging.getLogger(__name__)\n\nDEFAULT_ACTION_TIMEOUT = 60\n\n\n# Fabric environment level settings.\n# XXX: Note fabric env is a global singleton.\nenv.parallel = True  # By default, execute things in parallel. Uses multiprocessing under the hood.\nenv.user = cfg.CONF.system_user.user\nssh_key_file = cfg.CONF.system_user.ssh_key_file\n\nif ssh_key_file:\n    ssh_key_file = os.path.expanduser(ssh_key_file)\n\nif ssh_key_file and os.path.exists(ssh_key_file):\n    env.key_filename = ssh_key_file\n\nenv.timeout = 10  # Timeout for connections (in seconds)\nenv.command_timeout = DEFAULT_ACTION_TIMEOUT  # timeout for commands (in seconds)\nenv.combine_stderr = False\nenv.group = 'staff'\nenv.abort_exception = FabricExecutionFailureException\n\n# constants to lookup in runner_parameters.\nRUNNER_HOSTS = 'hosts'\nRUNNER_PARALLEL = 'parallel'\nRUNNER_SUDO = 'sudo'\nRUNNER_ON_BEHALF_USER = 'user'\nRUNNER_REMOTE_DIR = 'dir'\nRUNNER_COMMAND = 'cmd'\nRUNNER_KWARG_OP = 'kwarg_op'\nRUNNER_TIMEOUT = 'timeout'\n\n\ndef get_runner():\n    return FabricRunner(str(uuid.uuid4()))\n\n\nclass FabricRunner(ActionRunner, ShellRunnerMixin):\n    def __init__(self, runner_id):\n        super(FabricRunner, self).__init__(runner_id=runner_id)\n        self._hosts = None\n        self._parallel = True\n        self._sudo = False\n        self._on_behalf_user = None\n        self._user = None\n        self._kwarg_op = '--'\n\n    def pre_run(self):\n        LOG.debug('Entering FabricRunner.pre_run() for actionexec_id=\"%s\"',\n                  self.action_execution_id)\n        LOG.debug('    runner_parameters = %s', self.runner_parameters)\n        hosts = self.runner_parameters.get(RUNNER_HOSTS, '').split(',')\n        self._hosts = [h.strip() for h in hosts if len(h) > 0]\n        if len(self._hosts) < 1:\n            raise ActionRunnerPreRunError('No hosts specified to run action for action %s.',\n                                          self.action_execution_id)\n        self._parallel = self.runner_parameters.get(RUNNER_PARALLEL, True)\n        self._sudo = self.runner_parameters.get(RUNNER_SUDO, False)\n        self._sudo = self._sudo if self._sudo else False\n        self._on_behalf_user = self.context.get(RUNNER_ON_BEHALF_USER, env.user)\n        self._user = cfg.CONF.system_user.user\n        self._kwarg_op = self.runner_parameters.get(RUNNER_KWARG_OP, '--')\n        self._timeout = self.runner_parameters.get(RUNNER_TIMEOUT, DEFAULT_ACTION_TIMEOUT)\n\n        LOG.info('[FabricRunner=\"%s\", actionexec_id=\"%s\"] Finished pre_run.',\n                 self.runner_id, self.action_execution_id)\n\n    def run(self, action_parameters):\n        LOG.debug('    action_parameters = %s', action_parameters)\n        remote_action = self._get_fabric_remote_action(action_parameters) \\\n            if self.entry_point is None or len(self.entry_point) < 1 \\\n            else self._get_fabric_remote_script_action(action_parameters)\n        LOG.debug('Will execute remote_action : %s.', str(remote_action))\n        result = self._run(remote_action)\n        LOG.debug('Executed remote_action : %s. Result is : %s.', remote_action, result)\n        self.container_service.report_status(FabricRunner._get_result_status(\n            result, cfg.CONF.ssh_runner.allow_partial_failure))\n        self.container_service.report_result(result)\n\n        # TODO (manas) : figure out the right boolean representation.\n        return result is not None\n\n    def _run(self, remote_action):\n        LOG.info('Executing action via FabricRunner :%s for user: %s.',\n                 self.runner_id, remote_action.get_on_behalf_user())\n        LOG.info(('[Action info] name: %s, Id: %s, command: %s, on behalf user: %s, '\n                  'actual user: %s, sudo: %s'),\n                 remote_action.name, remote_action.action_exec_id, remote_action.get_command(),\n                 remote_action.get_on_behalf_user(), remote_action.get_user(),\n                 remote_action.is_sudo())\n        results = execute(remote_action.get_fabric_task(), hosts=remote_action.hosts)\n        return results\n\n    def _get_fabric_remote_action(self, action_paramaters):\n        command = self.runner_parameters.get(RUNNER_COMMAND, None)\n        env_vars = self._get_env_vars()\n        return FabricRemoteAction(self.action_name,\n                                  str(self.action_execution_id),\n                                  command,\n                                  env_vars=env_vars,\n                                  on_behalf_user=self._on_behalf_user,\n                                  user=self._user,\n                                  hosts=self._hosts,\n                                  parallel=self._parallel,\n                                  sudo=self._sudo,\n                                  timeout=self._timeout)\n\n    def _get_fabric_remote_script_action(self, action_parameters):\n        script_local_path_abs = self.entry_point\n        pos_args, named_args = self._get_script_args(action_parameters)\n        named_args = self._transform_named_args(named_args)\n        env_vars = self._get_env_vars()\n        remote_dir = self.runner_parameters.get(RUNNER_REMOTE_DIR,\n                                                cfg.CONF.ssh_runner.remote_dir)\n        remote_dir = os.path.join(remote_dir, self.action_execution_id)\n        return FabricRemoteScriptAction(self.action_name,\n                                        str(self.action_execution_id),\n                                        script_local_path_abs,\n                                        self.libs_dir_path,\n                                        named_args=named_args,\n                                        positional_args=pos_args,\n                                        env_vars=env_vars,\n                                        on_behalf_user=self._on_behalf_user,\n                                        user=self._user,\n                                        remote_dir=remote_dir,\n                                        hosts=self._hosts,\n                                        parallel=self._parallel,\n                                        sudo=self._sudo,\n                                        timeout=self._timeout)\n\n    def _get_env_vars(self):\n        return {'st2_auth_token': self.auth_token.token} if self.auth_token else {}\n\n    @staticmethod\n    def _get_result_status(result, allow_partial_failure):\n        success = not allow_partial_failure\n        for r in six.itervalues(result):\n            if allow_partial_failure:\n                success |= r.get('succeeded', False)\n                if success:\n                    return ACTIONEXEC_STATUS_SUCCEEDED\n            else:\n                success &= r.get('succeeded', False)\n                if not success:\n                    return ACTIONEXEC_STATUS_FAILED\n        return ACTIONEXEC_STATUS_SUCCEEDED if success else ACTIONEXEC_STATUS_FAILED\n\n\n# XXX: Write proper tests.\nif __name__ == '__main__':\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! NORMAL CMD !!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    runner = FabricRunner(str(uuid.uuid4()))\n    remote_action = FabricRemoteAction('UNAME', 'action_exec_id' + str(uuid.uuid4()), 'uname -a',\n                                       'narcissist', 'stanley', hosts=['54.191.85.86',\n                                       '54.191.17.38', '54.200.102.55'])\n    print(str(remote_action))\n    results = runner._run(remote_action)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! RESULTS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n\n    print(results)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! SUDO CMD !!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    runner = FabricRunner(str(uuid.uuid4()))\n    remote_action = FabricRemoteAction('UNAME', 'action_exec_id' + str(uuid.uuid4()), 'uname -a',\n                                       'narcissist', 'stanley', hosts=['54.191.85.86',\n                                       '54.191.17.38', '54.200.102.55'], parallel=True, sudo=True)\n    results = runner._run(remote_action)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! RESULTS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n\n    print(results)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! SCRIPT DAWG !!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    script_action = FabricRemoteScriptAction('UNAME', 'action_exec_id' + str(uuid.uuid4()),\n                                             '/tmp/ls-script.sh', named_args={},\n                                             positional_args='/tmp', on_behalf_user='narcissist',\n                                             user='stanley', hosts=['54.191.85.86'],\n                                             parallel=True, sudo=False)\n    results = runner._run(script_action)\n\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!! RESULTS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n    print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')\n\n    print(results)\n", "path": "st2actions/st2actions/runners/fabricrunner.py"}]}