diff --git a/doc/source/dsl/dsl_v2.rst b/doc/source/dsl/dsl_v2.rst index e364276c..f34ea606 100644 --- a/doc/source/dsl/dsl_v2.rst +++ b/doc/source/dsl/dsl_v2.rst @@ -759,7 +759,8 @@ Input parameters: - **host** - Host name that the command needs to be executed on. *Required*. - **username** - User name to authenticate on the host. -- **password** - User password to to authenticate on the host. +- **password** - User password to to authenticate on the host. *Optional.* +- **private_key** - Private key string which will be used for authentication on remote host. *Optional.* **NOTE**: Authentication using key pairs is supported, key should be on Mistral Executor server machine. diff --git a/mistral/actions/std_actions.py b/mistral/actions/std_actions.py index 85a5b9b2..6de61e97 100644 --- a/mistral/actions/std_actions.py +++ b/mistral/actions/std_actions.py @@ -327,11 +327,12 @@ class SSHAction(base.Action): same order as provided hosts. """ - def __init__(self, cmd, host, username, password): + def __init__(self, cmd, host, username, password=None, private_key=None): self.cmd = cmd self.host = host self.username = username self.password = password + self.private_key = private_key def run(self): def raise_exc(parent_exc=None): @@ -352,7 +353,9 @@ class SSHAction(base.Action): self.cmd, host_name, self.username, - self.password) + self.password, + pkey=self.private_key + ) if status_code > 0: return raise_exc() diff --git a/mistral/tests/unit/utils/test_inspect_utils.py b/mistral/tests/unit/utils/test_inspect_utils.py index b234c40c..aa94a8b8 100644 --- a/mistral/tests/unit/utils/test_inspect_utils.py +++ b/mistral/tests/unit/utils/test_inspect_utils.py @@ -15,6 +15,7 @@ from mistral.actions import std_actions from mistral.tests import base from mistral.utils import inspect_utils as i_u +from mistral.workflow import commands class InspectUtilsTest(base.BaseTest): @@ -32,7 +33,7 @@ class InspectUtilsTest(base.BaseTest): self.assertEqual(http_action_params, parameters_str) def test_get_parameters_str_all_mandatory(self): - action_class = std_actions.SSHAction - parameters_str = i_u.get_arg_list_as_str(action_class.__init__) + clazz = commands.RunTask + parameters_str = i_u.get_arg_list_as_str(clazz.__init__) - self.assertEqual("cmd, host, username, password", parameters_str) + self.assertEqual("wf_ex, task_spec, ctx", parameters_str) diff --git a/mistral/utils/ssh_utils.py b/mistral/utils/ssh_utils.py index 180ab30a..ae0186c1 100644 --- a/mistral/utils/ssh_utils.py +++ b/mistral/utils/ssh_utils.py @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import six + from oslo_log import log as logging import paramiko @@ -31,11 +33,15 @@ def _read_paramimko_stream(recv_func): return result -def _connect(host, username, password): +def _connect(host, username, password, pkey): + if pkey: + pkey = paramiko.RSAKey(file_obj=six.StringIO(pkey)) + LOG.debug('Creating SSH connection to %s' % host) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect(host, username=username, password=password) + ssh.connect(host, username=username, password=password, pkey=pkey) + return ssh @@ -43,9 +49,9 @@ def _cleanup(ssh): ssh.close() -def execute_command(cmd, host, username, password, +def execute_command(cmd, host, username, password=None, pkey=None, get_stderr=False, raise_when_error=True): - ssh = _connect(host, username, password) + ssh = _connect(host, username, password, pkey) LOG.debug("Executing command %s" % cmd)