Merge pull request #418 from darko-poljak/ssh-mux-opts
ssh multiplexing options
This commit is contained in:
		
				commit
				
					
						c790a2e906
					
				
			
		
					 4 changed files with 69 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -2,6 +2,7 @@ Changelog
 | 
			
		|||
---------
 | 
			
		||||
 | 
			
		||||
next:
 | 
			
		||||
	* Core: Add CDIST_REMOTE_COPY/EXEC env variables and multiplexing options for default scp/ssh (Darko Poljak)
 | 
			
		||||
	* Types: Remove bashisms in scripts (Darko Poljak)
 | 
			
		||||
	* Core: Fix bug in remote command with environment (Darko Poljak)
 | 
			
		||||
	* Core: Fix bug in local code execution (Darko Poljak)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
-----------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
#
 | 
			
		||||
# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org)
 | 
			
		||||
# 2016 Darko Poljak (darko.poljak at gmail.com)
 | 
			
		||||
#
 | 
			
		||||
# This file is part of cdist.
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +21,28 @@
 | 
			
		|||
#
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
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": control_path,
 | 
			
		||||
        "ControlMaster": "auto",
 | 
			
		||||
        "ControlPersist": "125",
 | 
			
		||||
    }
 | 
			
		||||
    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"""
 | 
			
		||||
    import argparse
 | 
			
		||||
| 
						 | 
				
			
			@ -27,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 = {}
 | 
			
		||||
| 
						 | 
				
			
			@ -73,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
 | 
			
		||||
| 
						 | 
				
			
			@ -101,6 +130,32 @@ 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 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()
 | 
			
		||||
            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
 | 
			
		||||
            # 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
 | 
			
		||||
            if args_dict['remote_copy'] is None:
 | 
			
		||||
                args.remote_copy = cdist.REMOTE_COPY + mux_opts
 | 
			
		||||
 | 
			
		||||
    log.debug(args)
 | 
			
		||||
    log.info("version %s" % cdist.VERSION)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue