Merge pull request #418 from darko-poljak/ssh-mux-opts

ssh multiplexing options
This commit is contained in:
Nico Schottelius 2016-03-31 21:41:13 +02:00
commit c790a2e906
4 changed files with 69 additions and 2 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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
-----------

View File

@ -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)