diff --git a/cdist/__init__.py b/cdist/__init__.py index 4454a3ac..e789499c 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -41,8 +41,8 @@ BANNER = """ "P' "" "" """ -REMOTE_COPY = "scp -o User=root -q" -REMOTE_EXEC = "ssh -o User=root -q" +REMOTE_COPY = "scp -o User=root" +REMOTE_EXEC = "ssh -o User=root" class Error(Exception): """Base exception class for this project""" diff --git a/cdist/exec/local.py b/cdist/exec/local.py index c0554831..15f49a89 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -33,6 +33,7 @@ import tempfile import cdist import cdist.message from cdist import core +import cdist.exec.util as exec_util class Local(object): """Execute commands locally. @@ -203,12 +204,14 @@ class Local(object): env.update(message.env) try: + output = exec_util.call_get_output(command, env=env) + self.log.debug("Local output: {}".format(output)) if return_output: - return subprocess.check_output(command, env=env).decode() - else: - subprocess.check_call(command, env=env) - except subprocess.CalledProcessError: - raise cdist.Error("Command failed: " + " ".join(command)) + return output.decode() + except subprocess.CalledProcessError as e: + raise cdist.Error("Command failed: " + " ".join(command) + + " with returncode: {} and output: {}".format( + e.returncode, e.output)) except OSError as error: raise cdist.Error(" ".join(command) + ": " + error.args[1]) finally: diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 77e2c8be..c78f02cb 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -26,6 +26,7 @@ import sys import glob import subprocess import logging +import cdist.exec.util as exec_util import cdist @@ -167,12 +168,14 @@ class Remote(object): self.log.debug("Remote run: %s", command) try: + output = exec_util.call_get_output(command, env=os_environ) + self.log.debug("Remote output: {}".format(output)) if return_output: - return subprocess.check_output(command, env=os_environ).decode() - else: - subprocess.check_call(command, env=os_environ) - except subprocess.CalledProcessError: - raise cdist.Error("Command failed: " + " ".join(command)) + return output.decode() + except subprocess.CalledProcessError as e: + raise cdist.Error("Command failed: " + " ".join(command) + + " with returncode: {} and output: {}".format( + e.returncode, e.output)) except OSError as error: raise cdist.Error(" ".join(command) + ": " + error.args[1]) except UnicodeDecodeError: diff --git a/cdist/exec/util.py b/cdist/exec/util.py new file mode 100644 index 00000000..983f455c --- /dev/null +++ b/cdist/exec/util.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# +# 2016 Darko Poljak (darko.poljak at gmail.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# + +import subprocess +from tempfile import TemporaryFile + +import cdist + +def call_get_output(command, env=None): + """Run the given command with the given environment. + Return the stdout and stderr output as a byte string. + """ + assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: {}".format(command) + + with TemporaryFile() as fout: + subprocess.check_call(command, env=env, + stdout=fout, stderr=subprocess.STDOUT) + fout.seek(0) + output = fout.read() + + return output diff --git a/docs/changelog b/docs/changelog index 207125db..eaed0eaa 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Custom: Add bash and zsh completions (Darko Poljak) + * Core: Improve error reporting for local and remote run command (Darko Poljak) * New type: __jail_freebsd9: Handle jail management on FreeBSD <= 9.X (Jake Guffey) * New type: __jail_freebsd10: Handle jail management on FreeBSD >= 10.0 (Jake Guffey) * Type __jail: Dynamically select the correct jail subtype based on target host OS (Jake Guffey) diff --git a/scripts/cdist b/scripts/cdist index 6baa28f3..55113be0 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -26,8 +26,11 @@ def inspect_ssh_mux_opts(control_path_dir="~/.ssh/"): import subprocess import os - control_path = os.path.join(control_path_dir, - "cdist.socket.master-%l-%r@%h:%p") + # socket is always local to each cdist run, it is created in + # temp directory that is created at starting cdist, so + # control_path file name can be static, it will always be + # unique due to unique temp directory name + control_path = os.path.join(control_path_dir, "ssh-control-path") wanted_mux_opts = { "ControlPath": control_path, "ControlMaster": "auto", @@ -147,7 +150,7 @@ def commandline(): # didn't specify command line options nor env vars: # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC if args_dict['remote_copy'] is None or args_dict['remote_exec'] is None: - control_path_dir = tempfile.mkdtemp() + control_path_dir = tempfile.mkdtemp(prefix="cdist") import atexit atexit.register(lambda: shutil.rmtree(control_path_dir)) mux_opts = inspect_ssh_mux_opts(control_path_dir)