From d0d0c258d65a29e674e8cbe7530b4fa45da6c4c7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 18 Mar 2016 23:34:02 +0100 Subject: [PATCH 1/5] Add ssh mux options by default if available. --- docs/man/cdist-reference.text.sh | 6 ++++ docs/man/man1/cdist.text | 5 +++ scripts/cdist | 60 ++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 0a9d76ef..0aaaec0a 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -249,6 +249,12 @@ CDIST_OVERRIDE:: CDIST_ORDER_DEPENDENCY:: Create dependencies based on the execution order (see cdist-manifest(7)) +CDIST_REMOTE_EXEC:: + Use this command for remote execution (should behave like ssh) + +CDIST_REMOTE_COPY:: + Use this command for remote copy (should behave like scp) + SEE ALSO -------- - cdist(1) diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index c09d8f41..e29ae3ae 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -138,6 +138,11 @@ CDIST_LOCAL_SHELL:: CDIST_REMOTE_SHELL:: Selects shell for remote scirpt execution, defaults to /bin/sh +CDIST_REMOTE_EXEC:: + Use this command for remote execution (should behave like ssh) + +CDIST_REMOTE_COPY:: + Use this command for remote copy (should behave like scp) EXIT STATUS ----------- diff --git a/scripts/cdist b/scripts/cdist index 8aa998d2..f5629641 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -21,33 +21,27 @@ # # -def inspect_ssh_mux_opts(): - import subprocess - +def inspect_ssh_mux_opts(control_path_dir="~/.ssh/"): """Inspect whether or not ssh supports multiplexing options""" + import subprocess + import os + + control_path = os.path.join(control_path_dir, "cdist.master-%l-%r@%h:%p") wanted_mux_opts = { - "ControlPath":"~/.ssh/master-%l-%r@%h:%p", - "ControlMaster":"auto", - "ControlPersist":"125", + "ControlPath": control_path, + "ControlMaster": "auto", + "ControlPersist": "125", } - # if checked key option is present then this assumes - # all options in value are present - check = { - "ControlMaster": ("ControlMaster", "ControlPath"), - "ControlPersist": ("ControlPersist",), - } - mux_opts = {} - for x in check: - try: - subprocess.check_output("ssh -o {}".format(x), - stderr=subprocess.STDOUT, shell=True) - except subprocess.CalledProcessError as e: - foo = e.output.decode().lower() - if not "bad configuration option" in foo: - for o in check[x]: - mux_opts[o] = wanted_mux_opts[o] - foo = [" -o {}={}".format(x, mux_opts[x]) for x in mux_opts] - return " ".join(foo) + mux_opts = " ".join([" -o {}={}".format(x, + wanted_mux_opts[x]) for x in wanted_mux_opts]) + try: + subprocess.check_output("ssh {}".format(mux_opts), + stderr=subprocess.STDOUT, shell=True) + except subprocess.CalledProcessError as e: + subproc_output = e.output.decode().lower() + if "bad configuration option" in subproc_output: + return "" + return mux_opts def commandline(): """Parse command line""" @@ -56,6 +50,9 @@ def commandline(): import cdist.banner import cdist.config import cdist.shell + import tempfile + import shutil + import os # Construct parser others can reuse parser = {} @@ -83,9 +80,18 @@ def commandline(): # Config # inspect multiplexing options for default remote copy/exec scp/ssh - MUX_OPTS = inspect_ssh_mux_opts() - cdist.REMOTE_EXEC += MUX_OPTS - cdist.REMOTE_COPY += MUX_OPTS + # but not if env vars are present + has_env_remote_exec = "CDIST_REMOTE_EXEC" in os.environ + has_env_remote_copy = "CDIST_REMOTE_COPY" in os.environ + if not has_env_remote_exec or not has_env_remote_copy: + control_path_dir = tempfile.mkdtemp(prefix="cdist.control.path") + import atexit + atexit.register(lambda: shutil.rmtree(control_path_dir)) + MUX_OPTS = inspect_ssh_mux_opts(control_path_dir) + if not has_env_remote_exec: + cdist.REMOTE_EXEC += MUX_OPTS + if not has_env_remote_copy: + cdist.REMOTE_COPY += MUX_OPTS parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) From d329db05e117a2e2ea755c8827aa75e8b3eb2891 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 18 Mar 2016 23:52:24 +0100 Subject: [PATCH 2/5] Apply CDIST_REMOTE_EXEC/COPY env vars. --- scripts/cdist | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/cdist b/scripts/cdist index f5629641..33105061 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -92,6 +92,10 @@ def commandline(): cdist.REMOTE_EXEC += MUX_OPTS if not has_env_remote_copy: cdist.REMOTE_COPY += MUX_OPTS + if has_env_remote_exec: + cdist.REMOTE_EXEC = os.environ['CDIST_REMOTE_EXEC'] + if has_env_remote_copy: + cdist.REMOTE_COPY = os.environ['CDIST_REMOTE_COPY'] parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) From 4318d72524f4569addf7bd06fd85e74dc5b054df Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 22 Mar 2016 08:41:51 +0100 Subject: [PATCH 3/5] No subprocess if user enters remote_exec/copy. --- scripts/cdist | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 33105061..265d73f0 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -79,24 +79,6 @@ def commandline(): parser['banner'].set_defaults(func=cdist.banner.banner) # Config - # inspect multiplexing options for default remote copy/exec scp/ssh - # but not if env vars are present - has_env_remote_exec = "CDIST_REMOTE_EXEC" in os.environ - has_env_remote_copy = "CDIST_REMOTE_COPY" in os.environ - if not has_env_remote_exec or not has_env_remote_copy: - control_path_dir = tempfile.mkdtemp(prefix="cdist.control.path") - import atexit - atexit.register(lambda: shutil.rmtree(control_path_dir)) - MUX_OPTS = inspect_ssh_mux_opts(control_path_dir) - if not has_env_remote_exec: - cdist.REMOTE_EXEC += MUX_OPTS - if not has_env_remote_copy: - cdist.REMOTE_COPY += MUX_OPTS - if has_env_remote_exec: - cdist.REMOTE_EXEC = os.environ['CDIST_REMOTE_EXEC'] - if has_env_remote_copy: - cdist.REMOTE_COPY = os.environ['CDIST_REMOTE_COPY'] - parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) parser['config'].add_argument('host', nargs='+', @@ -117,14 +99,17 @@ def commandline(): parser['config'].add_argument('-s', '--sequential', help='Operate on multiple hosts sequentially (default)', action='store_false', dest='parallel') + # remote-copy and remote-exec defaults are environment variables + # if set; if not then None - these will be futher handled after + # parsing to determine implementation default parser['config'].add_argument('--remote-copy', help='Command to use for remote copy (should behave like scp)', action='store', dest='remote_copy', - default=cdist.REMOTE_COPY) + default=os.environ.get('CDIST_REMOTE_COPY')) parser['config'].add_argument('--remote-exec', help='Command to use for remote execution (should behave like ssh)', action='store', dest='remote_exec', - default=cdist.REMOTE_EXEC) + default=os.environ.get('CDIST_REMOTE_EXEC')) parser['config'].set_defaults(func=cdist.config.Config.commandline) # Shell @@ -145,6 +130,21 @@ def commandline(): logging.root.setLevel(logging.INFO) if args.debug: logging.root.setLevel(logging.DEBUG) + args_dict = vars(args) + # if command with remote_copy and remote_exec params + if 'remote_copy' in args_dict and 'remote_exec' in args_dict: + # if remote-exec and/or remote-copy args are None then user + # 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(prefix="cdist.control.path") + import atexit + atexit.register(lambda: shutil.rmtree(control_path_dir)) + mux_opts = inspect_ssh_mux_opts(control_path_dir) + if args_dict['remote_exec'] is None: + args.remote_exec = cdist.REMOTE_EXEC + mux_opts + if args_dict['remote_copy'] is None: + args.remote_copy = cdist.REMOTE_COPY + mux_opts log.debug(args) log.info("version %s" % cdist.VERSION) From f6a5f56098fe4b6b8c113f2ef74ae0906f57d6f2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 26 Mar 2016 16:40:41 +0100 Subject: [PATCH 4/5] Use the same dir for ssh mux socket and Local base_path. --- scripts/cdist | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/cdist b/scripts/cdist index 265d73f0..9fa3ddb8 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -133,11 +133,16 @@ def commandline(): args_dict = vars(args) # if command with remote_copy and remote_exec params if 'remote_copy' in args_dict and 'remote_exec' in args_dict: + # if out_path is not set then create temp dir here so + # Local uses it for base_path and ssh mux socket is + # created in it. + if args_dict['out_path'] is None: + args.out_path = tempfile.mkdtemp() # if remote-exec and/or remote-copy args are None then user # 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(prefix="cdist.control.path") + control_path_dir = args.out_path import atexit atexit.register(lambda: shutil.rmtree(control_path_dir)) mux_opts = inspect_ssh_mux_opts(control_path_dir) From 0e2e90322b9e3eee18ec6f2fe824e73eaac7f663 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 27 Mar 2016 10:03:12 +0200 Subject: [PATCH 5/5] rmtree only if it is temp dir. If user specifies out_path then do not rmtree it. --- scripts/cdist | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 9fa3ddb8..fecf61d0 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -138,13 +138,19 @@ def commandline(): # created in it. if args_dict['out_path'] is None: args.out_path = tempfile.mkdtemp() + is_temp_dir = True + else: + is_temp_dir = False # if remote-exec and/or remote-copy args are None then user # 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 = args.out_path - import atexit - atexit.register(lambda: shutil.rmtree(control_path_dir)) + # only rmtree if it is temp directory; + # if user specifies out_path do not remove it + if is_temp_dir: + import atexit + atexit.register(lambda: shutil.rmtree(control_path_dir)) mux_opts = inspect_ssh_mux_opts(control_path_dir) if args_dict['remote_exec'] is None: args.remote_exec = cdist.REMOTE_EXEC + mux_opts