forked from ungleich-public/cdist
Merge remote-tracking branch 'ungleich/master' into cdist-type__hosts
This commit is contained in:
commit
13a5d4963b
14 changed files with 251 additions and 164 deletions
3
Makefile
3
Makefile
|
@ -246,3 +246,6 @@ pub:
|
||||||
|
|
||||||
test:
|
test:
|
||||||
$(helper) $@
|
$(helper) $@
|
||||||
|
|
||||||
|
pep8:
|
||||||
|
$(helper) $@
|
||||||
|
|
|
@ -249,7 +249,7 @@ eof
|
||||||
# First check everything is sane
|
# First check everything is sane
|
||||||
"$0" check-date
|
"$0" check-date
|
||||||
"$0" check-unittest
|
"$0" check-unittest
|
||||||
"$0" pep8
|
"$0" check-pep8
|
||||||
|
|
||||||
# Generate version file to be included in packaging
|
# Generate version file to be included in packaging
|
||||||
"$0" target-version
|
"$0" target-version
|
||||||
|
@ -360,7 +360,11 @@ eof
|
||||||
;;
|
;;
|
||||||
|
|
||||||
pep8)
|
pep8)
|
||||||
pep8 ${basedir} | less
|
pep8 "${basedir}" "${basedir}/scripts/cdist" | less
|
||||||
|
;;
|
||||||
|
|
||||||
|
check-pep8)
|
||||||
|
"$0" pep8
|
||||||
echo "Please review pep8 report."
|
echo "Please review pep8 report."
|
||||||
while true
|
while true
|
||||||
do
|
do
|
||||||
|
|
|
@ -284,7 +284,7 @@ eof
|
||||||
# First check everything is sane
|
# First check everything is sane
|
||||||
"$0" check-date
|
"$0" check-date
|
||||||
"$0" check-unittest
|
"$0" check-unittest
|
||||||
"$0" pep8
|
"$0" check-pep8
|
||||||
|
|
||||||
# Generate version file to be included in packaging
|
# Generate version file to be included in packaging
|
||||||
"$0" target-version
|
"$0" target-version
|
||||||
|
@ -422,7 +422,11 @@ eof
|
||||||
;;
|
;;
|
||||||
|
|
||||||
pep8)
|
pep8)
|
||||||
pep8 ${basedir} | less
|
pep8 "${basedir}" "${basedir}/scripts/cdist" | less
|
||||||
|
;;
|
||||||
|
|
||||||
|
check-pep8)
|
||||||
|
"$0" pep8
|
||||||
echo "Please review pep8 report."
|
echo "Please review pep8 report."
|
||||||
while true
|
while true
|
||||||
do
|
do
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import hashlib
|
||||||
|
|
||||||
import cdist.version
|
import cdist.version
|
||||||
|
|
||||||
|
@ -82,3 +83,11 @@ def file_to_list(filename):
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def str_hash(s):
|
||||||
|
"""Return hash of string s"""
|
||||||
|
if isinstance(s, str):
|
||||||
|
return hashlib.md5(s.encode('utf-8')).hexdigest()
|
||||||
|
else:
|
||||||
|
raise Error("Param should be string")
|
||||||
|
|
|
@ -27,6 +27,7 @@ import sys
|
||||||
import time
|
import time
|
||||||
import pprint
|
import pprint
|
||||||
import itertools
|
import itertools
|
||||||
|
import tempfile
|
||||||
|
|
||||||
import cdist
|
import cdist
|
||||||
|
|
||||||
|
@ -36,6 +37,36 @@ import cdist.exec.remote
|
||||||
from cdist import core
|
from cdist import core
|
||||||
|
|
||||||
|
|
||||||
|
def inspect_ssh_mux_opts():
|
||||||
|
"""Inspect whether or not ssh supports multiplexing options.
|
||||||
|
|
||||||
|
Return string containing multiplexing options if supported.
|
||||||
|
If ControlPath is supported then placeholder for that path is
|
||||||
|
specified and can be used for final string formatting.
|
||||||
|
For example, this function can return string:
|
||||||
|
"-o ControlMaster=auto -o ControlPersist=125 -o ControlPath={}".
|
||||||
|
Then it can be formatted:
|
||||||
|
mux_opts_string.format('/tmp/tmpxxxxxx/ssh-control-path').
|
||||||
|
"""
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
wanted_mux_opts = {
|
||||||
|
"ControlPath": "{}",
|
||||||
|
"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
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
"""Cdist main class to hold arbitrary data"""
|
"""Cdist main class to hold arbitrary data"""
|
||||||
|
|
||||||
|
@ -94,7 +125,6 @@ class Config(object):
|
||||||
initial_manifest_tempfile = None
|
initial_manifest_tempfile = None
|
||||||
if args.manifest == '-':
|
if args.manifest == '-':
|
||||||
# read initial manifest from stdin
|
# read initial manifest from stdin
|
||||||
import tempfile
|
|
||||||
try:
|
try:
|
||||||
handle, initial_manifest_temp_path = tempfile.mkstemp(
|
handle, initial_manifest_temp_path = tempfile.mkstemp(
|
||||||
prefix='cdist.stdin.')
|
prefix='cdist.stdin.')
|
||||||
|
@ -112,18 +142,47 @@ class Config(object):
|
||||||
failed_hosts = []
|
failed_hosts = []
|
||||||
time_start = time.time()
|
time_start = time.time()
|
||||||
|
|
||||||
|
# default remote cmd patterns
|
||||||
|
args.remote_exec_pattern = None
|
||||||
|
args.remote_copy_pattern = None
|
||||||
|
|
||||||
|
args_dict = vars(args)
|
||||||
|
# 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):
|
||||||
|
mux_opts = inspect_ssh_mux_opts()
|
||||||
|
if args_dict['remote_exec'] is None:
|
||||||
|
args.remote_exec_pattern = cdist.REMOTE_EXEC + mux_opts
|
||||||
|
if args_dict['remote_copy'] is None:
|
||||||
|
args.remote_copy_pattern = cdist.REMOTE_COPY + mux_opts
|
||||||
|
|
||||||
|
if args.out_path:
|
||||||
|
base_root_path = args.out_path
|
||||||
|
else:
|
||||||
|
base_root_path = tempfile.mkdtemp()
|
||||||
|
|
||||||
hostcnt = 0
|
hostcnt = 0
|
||||||
for host in itertools.chain(cls.hosts(args.host),
|
for host in itertools.chain(cls.hosts(args.host),
|
||||||
cls.hosts(args.hostfile)):
|
cls.hosts(args.hostfile)):
|
||||||
|
hostdir = cdist.str_hash(host)
|
||||||
|
host_base_path = os.path.join(base_root_path, hostdir)
|
||||||
|
|
||||||
|
log.debug("Base root path for target host \"{}\" is \"{}\"".format(
|
||||||
|
host, host_base_path))
|
||||||
|
|
||||||
hostcnt += 1
|
hostcnt += 1
|
||||||
if args.parallel:
|
if args.parallel:
|
||||||
log.debug("Creating child process for %s", host)
|
log.debug("Creating child process for %s", host)
|
||||||
process[host] = multiprocessing.Process(
|
process[host] = multiprocessing.Process(
|
||||||
target=cls.onehost, args=(host, args, True))
|
target=cls.onehost,
|
||||||
|
args=(host, host_base_path, hostdir, args, True))
|
||||||
process[host].start()
|
process[host].start()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
cls.onehost(host, args, parallel=False)
|
cls.onehost(host, host_base_path, hostdir,
|
||||||
|
args, parallel=False)
|
||||||
except cdist.Error as e:
|
except cdist.Error as e:
|
||||||
failed_hosts.append(host)
|
failed_hosts.append(host)
|
||||||
|
|
||||||
|
@ -145,22 +204,42 @@ class Config(object):
|
||||||
" ".join(failed_hosts))
|
" ".join(failed_hosts))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def onehost(cls, host, args, parallel):
|
def onehost(cls, host, host_base_path, host_dir_name, args, parallel):
|
||||||
"""Configure ONE system"""
|
"""Configure ONE system"""
|
||||||
|
|
||||||
log = logging.getLogger(host)
|
log = logging.getLogger(host)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
control_path = os.path.join(host_base_path, "ssh-control-path")
|
||||||
|
# If we constructed patterns for remote commands then there is
|
||||||
|
# placeholder for ssh ControlPath, format it and we have unique
|
||||||
|
# ControlPath for each host.
|
||||||
|
#
|
||||||
|
# If not then use args.remote_exec/copy that user specified.
|
||||||
|
if args.remote_exec_pattern:
|
||||||
|
remote_exec = args.remote_exec_pattern.format(control_path)
|
||||||
|
else:
|
||||||
|
remote_exec = args.remote_exec
|
||||||
|
if args.remote_copy_pattern:
|
||||||
|
remote_copy = args.remote_copy_pattern.format(control_path)
|
||||||
|
else:
|
||||||
|
remote_copy = args.remote_copy
|
||||||
|
log.debug("remote_exec for host \"{}\": {}".format(
|
||||||
|
host, remote_exec))
|
||||||
|
log.debug("remote_copy for host \"{}\": {}".format(
|
||||||
|
host, remote_copy))
|
||||||
|
|
||||||
local = cdist.exec.local.Local(
|
local = cdist.exec.local.Local(
|
||||||
target_host=host,
|
target_host=host,
|
||||||
|
base_root_path=host_base_path,
|
||||||
|
host_dir_name=host_dir_name,
|
||||||
initial_manifest=args.manifest,
|
initial_manifest=args.manifest,
|
||||||
base_path=args.out_path,
|
|
||||||
add_conf_dirs=args.conf_dir)
|
add_conf_dirs=args.conf_dir)
|
||||||
|
|
||||||
remote = cdist.exec.remote.Remote(
|
remote = cdist.exec.remote.Remote(
|
||||||
target_host=host,
|
target_host=host,
|
||||||
remote_exec=args.remote_exec,
|
remote_exec=remote_exec,
|
||||||
remote_copy=args.remote_copy)
|
remote_copy=remote_copy)
|
||||||
|
|
||||||
c = cls(local, remote, dry_run=args.dry_run)
|
c = cls(local, remote, dry_run=args.dry_run)
|
||||||
c.run()
|
c.run()
|
||||||
|
|
|
@ -29,7 +29,6 @@ import subprocess
|
||||||
import shutil
|
import shutil
|
||||||
import logging
|
import logging
|
||||||
import tempfile
|
import tempfile
|
||||||
import hashlib
|
|
||||||
|
|
||||||
import cdist
|
import cdist
|
||||||
import cdist.message
|
import cdist.message
|
||||||
|
@ -48,40 +47,25 @@ class Local(object):
|
||||||
"""
|
"""
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
target_host,
|
target_host,
|
||||||
|
base_root_path,
|
||||||
|
host_dir_name,
|
||||||
exec_path=sys.argv[0],
|
exec_path=sys.argv[0],
|
||||||
initial_manifest=None,
|
initial_manifest=None,
|
||||||
base_path=None,
|
|
||||||
add_conf_dirs=None):
|
add_conf_dirs=None):
|
||||||
|
|
||||||
self.target_host = target_host
|
self.target_host = target_host
|
||||||
self._init_log()
|
self.hostdir = host_dir_name
|
||||||
|
self.base_path = os.path.join(base_root_path, "data")
|
||||||
# FIXME: stopped: create base that does not require moving later
|
|
||||||
if base_path:
|
|
||||||
base_path_parent = base_path
|
|
||||||
else:
|
|
||||||
base_path_parent = tempfile.mkdtemp()
|
|
||||||
# TODO: the below atexit hook nukes any debug info we would have
|
|
||||||
# if cdist exits with error.
|
|
||||||
# import atexit
|
|
||||||
# atexit.register(lambda: shutil.rmtree(base_path_parent))
|
|
||||||
self.hostdir = self._hostdir()
|
|
||||||
self.log.info("Calculated temp dir for target \"{}\" is "
|
|
||||||
"\"{}\"".format(self.target_host, self.hostdir))
|
|
||||||
self.base_path = os.path.join(base_path_parent, self.hostdir)
|
|
||||||
|
|
||||||
self._init_permissions()
|
|
||||||
|
|
||||||
self.mkdir(self.base_path)
|
|
||||||
|
|
||||||
# FIXME: as well
|
|
||||||
self._init_cache_dir(None)
|
|
||||||
|
|
||||||
self.exec_path = exec_path
|
self.exec_path = exec_path
|
||||||
self.custom_initial_manifest = initial_manifest
|
self.custom_initial_manifest = initial_manifest
|
||||||
|
|
||||||
self._add_conf_dirs = add_conf_dirs
|
self._add_conf_dirs = add_conf_dirs
|
||||||
|
|
||||||
|
self._init_log()
|
||||||
|
self._init_permissions()
|
||||||
|
self.mkdir(self.base_path)
|
||||||
|
# FIXME: create dir that does not require moving later
|
||||||
|
self._init_cache_dir(None)
|
||||||
self._init_paths()
|
self._init_paths()
|
||||||
self._init_object_marker()
|
self._init_object_marker()
|
||||||
self._init_conf_dirs()
|
self._init_conf_dirs()
|
||||||
|
@ -98,12 +82,6 @@ class Local(object):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _hostdir(self):
|
|
||||||
# Do not assume target_host is anything that can be used as a
|
|
||||||
# directory name.
|
|
||||||
# Instead use a hash, which is known to work as directory name.
|
|
||||||
return hashlib.md5(self.target_host.encode('utf-8')).hexdigest()
|
|
||||||
|
|
||||||
def _init_log(self):
|
def _init_log(self):
|
||||||
self.log = logging.getLogger(self.target_host)
|
self.log = logging.getLogger(self.target_host)
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,13 @@ class CodeTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.local_dir = self.mkdtemp()
|
self.local_dir = self.mkdtemp()
|
||||||
|
self.hostdir = cdist.str_hash(self.target_host)
|
||||||
|
self.host_base_path = os.path.join(self.local_dir, self.hostdir)
|
||||||
|
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=self.local_dir,
|
base_root_path=self.host_base_path,
|
||||||
|
host_dir_name=self.hostdir,
|
||||||
exec_path=cdist.test.cdist_exec_path,
|
exec_path=cdist.test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir])
|
add_conf_dirs=[conf_dir])
|
||||||
self.local.create_files_dirs()
|
self.local.create_files_dirs()
|
||||||
|
|
|
@ -55,10 +55,13 @@ class ConfigRunTestCase(test.CdistTestCase):
|
||||||
self.temp_dir = self.mkdtemp()
|
self.temp_dir = self.mkdtemp()
|
||||||
|
|
||||||
self.local_dir = os.path.join(self.temp_dir, "local")
|
self.local_dir = os.path.join(self.temp_dir, "local")
|
||||||
os.mkdir(self.local_dir)
|
self.hostdir = cdist.str_hash(self.target_host)
|
||||||
|
self.host_base_path = os.path.join(self.local_dir, self.hostdir)
|
||||||
|
os.makedirs(self.host_base_path)
|
||||||
self.local = cdist.exec.local.Local(
|
self.local = cdist.exec.local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=self.local_dir)
|
base_root_path=self.host_base_path,
|
||||||
|
host_dir_name=self.hostdir)
|
||||||
|
|
||||||
# Setup test objects
|
# Setup test objects
|
||||||
self.object_base_path = op.join(self.temp_dir, 'object')
|
self.object_base_path = op.join(self.temp_dir, 'object')
|
||||||
|
@ -161,7 +164,8 @@ class ConfigRunTestCase(test.CdistTestCase):
|
||||||
"""Test if the dryrun option is working like expected"""
|
"""Test if the dryrun option is working like expected"""
|
||||||
drylocal = cdist.exec.local.Local(
|
drylocal = cdist.exec.local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=self.local_dir,
|
base_root_path=self.host_base_path,
|
||||||
|
host_dir_name=self.hostdir,
|
||||||
# exec_path can not derivated from sys.argv in case of unittest
|
# exec_path can not derivated from sys.argv in case of unittest
|
||||||
exec_path=os.path.abspath(os.path.join(
|
exec_path=os.path.abspath(os.path.join(
|
||||||
my_dir, '../../../scripts/cdist')),
|
my_dir, '../../../scripts/cdist')),
|
||||||
|
@ -184,3 +188,8 @@ class ConfigRunTestCase(test.CdistTestCase):
|
||||||
# first.requirements = ['__singleton_test/foo']
|
# first.requirements = ['__singleton_test/foo']
|
||||||
# with self.assertRaises(cdist.core.?????):
|
# with self.assertRaises(cdist.core.?????):
|
||||||
# self.config.iterate_until_finished()
|
# self.config.iterate_until_finished()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
unittest.main()
|
||||||
|
|
|
@ -48,10 +48,13 @@ class EmulatorTestCase(test.CdistTestCase):
|
||||||
handle, self.script = self.mkstemp(dir=self.temp_dir)
|
handle, self.script = self.mkstemp(dir=self.temp_dir)
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
base_path = self.temp_dir
|
base_path = self.temp_dir
|
||||||
|
hostdir = cdist.str_hash(self.target_host)
|
||||||
|
host_base_path = os.path.join(base_path, hostdir)
|
||||||
|
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=base_path,
|
base_root_path=host_base_path,
|
||||||
|
host_dir_name=hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir])
|
add_conf_dirs=[conf_dir])
|
||||||
self.local.create_files_dirs()
|
self.local.create_files_dirs()
|
||||||
|
@ -148,10 +151,13 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase):
|
||||||
handle, self.script = self.mkstemp(dir=self.temp_dir)
|
handle, self.script = self.mkstemp(dir=self.temp_dir)
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
base_path = self.temp_dir
|
base_path = self.temp_dir
|
||||||
|
hostdir = cdist.str_hash(self.target_host)
|
||||||
|
host_base_path = os.path.join(base_path, hostdir)
|
||||||
|
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=base_path,
|
base_root_path=host_base_path,
|
||||||
|
host_dir_name=hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir])
|
add_conf_dirs=[conf_dir])
|
||||||
self.local.create_files_dirs()
|
self.local.create_files_dirs()
|
||||||
|
@ -235,10 +241,13 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.temp_dir = self.mkdtemp()
|
self.temp_dir = self.mkdtemp()
|
||||||
base_path = os.path.join(self.temp_dir, "out")
|
base_path = os.path.join(self.temp_dir, "out")
|
||||||
|
hostdir = cdist.str_hash(self.target_host)
|
||||||
|
host_base_path = os.path.join(base_path, hostdir)
|
||||||
|
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=base_path,
|
base_root_path=host_base_path,
|
||||||
|
host_dir_name=hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir])
|
add_conf_dirs=[conf_dir])
|
||||||
self.local.create_files_dirs()
|
self.local.create_files_dirs()
|
||||||
|
@ -265,10 +274,13 @@ class OverrideTestCase(test.CdistTestCase):
|
||||||
handle, self.script = self.mkstemp(dir=self.temp_dir)
|
handle, self.script = self.mkstemp(dir=self.temp_dir)
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
base_path = self.temp_dir
|
base_path = self.temp_dir
|
||||||
|
hostdir = cdist.str_hash(self.target_host)
|
||||||
|
host_base_path = os.path.join(base_path, hostdir)
|
||||||
|
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=base_path,
|
base_root_path=host_base_path,
|
||||||
|
host_dir_name=hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir])
|
add_conf_dirs=[conf_dir])
|
||||||
self.local.create_files_dirs()
|
self.local.create_files_dirs()
|
||||||
|
@ -303,12 +315,15 @@ class ArgumentsTestCase(test.CdistTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.temp_dir = self.mkdtemp()
|
self.temp_dir = self.mkdtemp()
|
||||||
base_path = self.temp_dir
|
base_path = self.temp_dir
|
||||||
|
hostdir = cdist.str_hash(self.target_host)
|
||||||
|
host_base_path = os.path.join(base_path, hostdir)
|
||||||
handle, self.script = self.mkstemp(dir=self.temp_dir)
|
handle, self.script = self.mkstemp(dir=self.temp_dir)
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
|
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=base_path,
|
base_root_path=host_base_path,
|
||||||
|
host_dir_name=hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir])
|
add_conf_dirs=[conf_dir])
|
||||||
self.local.create_files_dirs()
|
self.local.create_files_dirs()
|
||||||
|
@ -425,10 +440,13 @@ class StdinTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
self.temp_dir = self.mkdtemp()
|
self.temp_dir = self.mkdtemp()
|
||||||
base_path = os.path.join(self.temp_dir, "out")
|
base_path = os.path.join(self.temp_dir, "out")
|
||||||
|
hostdir = cdist.str_hash(self.target_host)
|
||||||
|
host_base_path = os.path.join(base_path, hostdir)
|
||||||
|
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=base_path,
|
base_root_path=host_base_path,
|
||||||
|
host_dir_name=hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir])
|
add_conf_dirs=[conf_dir])
|
||||||
|
|
||||||
|
|
|
@ -47,11 +47,14 @@ class LocalTestCase(test.CdistTestCase):
|
||||||
target_host = 'localhost'
|
target_host = 'localhost'
|
||||||
self.temp_dir = self.mkdtemp()
|
self.temp_dir = self.mkdtemp()
|
||||||
self.out_parent_path = self.temp_dir
|
self.out_parent_path = self.temp_dir
|
||||||
self.out_path = op.join(self.out_parent_path, target_host)
|
self.hostdir = cdist.str_hash(target_host)
|
||||||
|
self.host_base_path = op.join(self.out_parent_path, self.hostdir)
|
||||||
|
self.out_path = op.join(self.host_base_path, "data")
|
||||||
|
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=target_host,
|
target_host=target_host,
|
||||||
base_path=self.out_parent_path,
|
base_root_path=self.host_base_path,
|
||||||
|
host_dir_name=self.hostdir,
|
||||||
exec_path=test.cdist_exec_path
|
exec_path=test.cdist_exec_path
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -109,7 +112,8 @@ class LocalTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
link_test_local = local.Local(
|
link_test_local = local.Local(
|
||||||
target_host='localhost',
|
target_host='localhost',
|
||||||
base_path=self.out_parent_path,
|
base_root_path=self.host_base_path,
|
||||||
|
host_dir_name=self.hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -127,7 +131,8 @@ class LocalTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
link_test_local = local.Local(
|
link_test_local = local.Local(
|
||||||
target_host='localhost',
|
target_host='localhost',
|
||||||
base_path=self.out_parent_path,
|
base_root_path=self.host_base_path,
|
||||||
|
host_dir_name=self.hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir]
|
add_conf_dirs=[conf_dir]
|
||||||
)
|
)
|
||||||
|
@ -148,7 +153,8 @@ class LocalTestCase(test.CdistTestCase):
|
||||||
|
|
||||||
link_test_local = local.Local(
|
link_test_local = local.Local(
|
||||||
target_host='localhost',
|
target_host='localhost',
|
||||||
base_path=self.out_parent_path,
|
base_root_path=self.host_base_path,
|
||||||
|
host_dir_name=self.hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -42,12 +42,15 @@ class ExplorerClassTestCase(test.CdistTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.temp_dir = self.mkdtemp()
|
self.temp_dir = self.mkdtemp()
|
||||||
self.local_path = os.path.join(self.temp_dir, "local")
|
self.local_path = os.path.join(self.temp_dir, "local")
|
||||||
|
hostdir = cdist.str_hash(self.target_host)
|
||||||
|
base_root_path = os.path.join(self.local_path, hostdir)
|
||||||
self.remote_base_path = os.path.join(self.temp_dir, "remote")
|
self.remote_base_path = os.path.join(self.temp_dir, "remote")
|
||||||
os.makedirs(self.remote_base_path)
|
os.makedirs(self.remote_base_path)
|
||||||
|
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=self.local_path,
|
base_root_path=base_root_path,
|
||||||
|
host_dir_name=hostdir,
|
||||||
exec_path=test.cdist_exec_path,
|
exec_path=test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir],
|
add_conf_dirs=[conf_dir],
|
||||||
)
|
)
|
||||||
|
|
|
@ -49,9 +49,12 @@ class ManifestTestCase(test.CdistTestCase):
|
||||||
self.temp_dir = self.mkdtemp()
|
self.temp_dir = self.mkdtemp()
|
||||||
|
|
||||||
out_path = self.temp_dir
|
out_path = self.temp_dir
|
||||||
|
hostdir = cdist.str_hash(self.target_host)
|
||||||
|
base_root_path = os.path.join(out_path, hostdir)
|
||||||
self.local = local.Local(
|
self.local = local.Local(
|
||||||
target_host=self.target_host,
|
target_host=self.target_host,
|
||||||
base_path=out_path,
|
base_root_path=base_root_path,
|
||||||
|
host_dir_name=hostdir,
|
||||||
exec_path=cdist.test.cdist_exec_path,
|
exec_path=cdist.test.cdist_exec_path,
|
||||||
add_conf_dirs=[conf_dir])
|
add_conf_dirs=[conf_dir])
|
||||||
self.local.create_files_dirs()
|
self.local.create_files_dirs()
|
||||||
|
|
|
@ -4,6 +4,12 @@ Changelog
|
||||||
next:
|
next:
|
||||||
* New type: __hosts: manage entries in /etc/hosts (Dmitry Bogatov)
|
* New type: __hosts: manage entries in /etc/hosts (Dmitry Bogatov)
|
||||||
|
|
||||||
|
4.2.2: 2016-07-26
|
||||||
|
* Core: Fix ssh ControlPath socket file error (Darko Poljak)
|
||||||
|
* Documentation: Update cdist man page and cdist-references (Darko Poljak)
|
||||||
|
* Documentation: Change cdist and cdist-type__pyvenv man page licenses to GPLv3+ (Darko Poljak)
|
||||||
|
* Documentation: Add FILES to cdist man page (Darko Poljak)
|
||||||
|
|
||||||
4.2.1: 2016-07-18
|
4.2.1: 2016-07-18
|
||||||
* Build: Fix signed release (Darko Poljak)
|
* Build: Fix signed release (Darko Poljak)
|
||||||
* Build: Fix building docs (Darko Poljak)
|
* Build: Fix building docs (Darko Poljak)
|
||||||
|
|
120
scripts/cdist
120
scripts/cdist
|
@ -21,31 +21,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
def inspect_ssh_mux_opts(control_path_dir="~/.ssh/"):
|
|
||||||
"""Inspect whether or not ssh supports multiplexing options"""
|
|
||||||
import subprocess
|
|
||||||
import os
|
|
||||||
|
|
||||||
# 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",
|
|
||||||
"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():
|
def commandline():
|
||||||
"""Parse command line"""
|
"""Parse command line"""
|
||||||
|
@ -54,7 +29,6 @@ def commandline():
|
||||||
import cdist.banner
|
import cdist.banner
|
||||||
import cdist.config
|
import cdist.config
|
||||||
import cdist.shell
|
import cdist.shell
|
||||||
import tempfile
|
|
||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -62,63 +36,71 @@ def commandline():
|
||||||
parser = {}
|
parser = {}
|
||||||
# Options _all_ parsers have in common
|
# Options _all_ parsers have in common
|
||||||
parser['loglevel'] = argparse.ArgumentParser(add_help=False)
|
parser['loglevel'] = argparse.ArgumentParser(add_help=False)
|
||||||
parser['loglevel'].add_argument('-d', '--debug',
|
parser['loglevel'].add_argument(
|
||||||
help='Set log level to debug', action='store_true',
|
'-d', '--debug', help='Set log level to debug',
|
||||||
default=False)
|
action='store_true', default=False)
|
||||||
parser['loglevel'].add_argument('-v', '--verbose',
|
parser['loglevel'].add_argument(
|
||||||
help='Set log level to info, be more verbose',
|
'-v', '--verbose', help='Set log level to info, be more verbose',
|
||||||
action='store_true', default=False)
|
action='store_true', default=False)
|
||||||
|
|
||||||
# Main subcommand parser
|
# Main subcommand parser
|
||||||
parser['main'] = argparse.ArgumentParser(description='cdist '
|
parser['main'] = argparse.ArgumentParser(
|
||||||
+ cdist.VERSION,
|
description='cdist ' + cdist.VERSION, parents=[parser['loglevel']])
|
||||||
parents=[parser['loglevel']])
|
parser['main'].add_argument(
|
||||||
parser['main'].add_argument('-V', '--version',
|
'-V', '--version', help='Show version', action='version',
|
||||||
help='Show version', action='version',
|
|
||||||
version='%(prog)s ' + cdist.VERSION)
|
version='%(prog)s ' + cdist.VERSION)
|
||||||
parser['sub'] = parser['main'].add_subparsers(title="Commands",
|
parser['sub'] = parser['main'].add_subparsers(
|
||||||
dest="command")
|
title="Commands", dest="command")
|
||||||
|
|
||||||
# Banner
|
# Banner
|
||||||
parser['banner'] = parser['sub'].add_parser('banner',
|
parser['banner'] = parser['sub'].add_parser(
|
||||||
parents=[parser['loglevel']])
|
'banner', parents=[parser['loglevel']])
|
||||||
parser['banner'].set_defaults(func=cdist.banner.banner)
|
parser['banner'].set_defaults(func=cdist.banner.banner)
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
parser['config'] = parser['sub'].add_parser('config',
|
parser['config'] = parser['sub'].add_parser(
|
||||||
parents=[parser['loglevel']])
|
'config', parents=[parser['loglevel']])
|
||||||
parser['config'].add_argument('host', nargs='*',
|
parser['config'].add_argument(
|
||||||
help='host(s) to operate on')
|
'host', nargs='*', help='host(s) to operate on')
|
||||||
parser['config'].add_argument('-c', '--conf-dir',
|
parser['config'].add_argument(
|
||||||
|
'-c', '--conf-dir',
|
||||||
help=('Add configuration directory (can be repeated, '
|
help=('Add configuration directory (can be repeated, '
|
||||||
'last one wins)'), action='append')
|
'last one wins)'), action='append')
|
||||||
parser['config'].add_argument('-f', '--file',
|
parser['config'].add_argument(
|
||||||
|
'-f', '--file',
|
||||||
help=('Read additional hosts to operate on from specified file '
|
help=('Read additional hosts to operate on from specified file '
|
||||||
'or from stdin if \'-\' (each host on separate line). '
|
'or from stdin if \'-\' (each host on separate line). '
|
||||||
'If no host or host file is specified then, by default, '
|
'If no host or host file is specified then, by default, '
|
||||||
'read hosts from stdin.'),
|
'read hosts from stdin.'),
|
||||||
dest='hostfile', required=False)
|
dest='hostfile', required=False)
|
||||||
parser['config'].add_argument('-i', '--initial-manifest',
|
parser['config'].add_argument(
|
||||||
|
'-i', '--initial-manifest',
|
||||||
help='Path to a cdist manifest or \'-\' to read from stdin.',
|
help='Path to a cdist manifest or \'-\' to read from stdin.',
|
||||||
dest='manifest', required=False)
|
dest='manifest', required=False)
|
||||||
parser['config'].add_argument('-n', '--dry-run',
|
parser['config'].add_argument(
|
||||||
|
'-n', '--dry-run',
|
||||||
help='Do not execute code', action='store_true')
|
help='Do not execute code', action='store_true')
|
||||||
parser['config'].add_argument('-o', '--out-dir',
|
parser['config'].add_argument(
|
||||||
|
'-o', '--out-dir',
|
||||||
help='Directory to save cdist output in', dest="out_path")
|
help='Directory to save cdist output in', dest="out_path")
|
||||||
parser['config'].add_argument('-p', '--parallel',
|
parser['config'].add_argument(
|
||||||
|
'-p', '--parallel',
|
||||||
help='Operate on multiple hosts in parallel',
|
help='Operate on multiple hosts in parallel',
|
||||||
action='store_true', dest='parallel')
|
action='store_true', dest='parallel')
|
||||||
parser['config'].add_argument('-s', '--sequential',
|
parser['config'].add_argument(
|
||||||
|
'-s', '--sequential',
|
||||||
help='Operate on multiple hosts sequentially (default)',
|
help='Operate on multiple hosts sequentially (default)',
|
||||||
action='store_false', dest='parallel')
|
action='store_false', dest='parallel')
|
||||||
# remote-copy and remote-exec defaults are environment variables
|
# remote-copy and remote-exec defaults are environment variables
|
||||||
# if set; if not then None - these will be futher handled after
|
# if set; if not then None - these will be futher handled after
|
||||||
# parsing to determine implementation default
|
# parsing to determine implementation default
|
||||||
parser['config'].add_argument('--remote-copy',
|
parser['config'].add_argument(
|
||||||
|
'--remote-copy',
|
||||||
help='Command to use for remote copy (should behave like scp)',
|
help='Command to use for remote copy (should behave like scp)',
|
||||||
action='store', dest='remote_copy',
|
action='store', dest='remote_copy',
|
||||||
default=os.environ.get('CDIST_REMOTE_COPY'))
|
default=os.environ.get('CDIST_REMOTE_COPY'))
|
||||||
parser['config'].add_argument('--remote-exec',
|
parser['config'].add_argument(
|
||||||
|
'--remote-exec',
|
||||||
help=('Command to use for remote execution '
|
help=('Command to use for remote execution '
|
||||||
'(should behave like ssh)'),
|
'(should behave like ssh)'),
|
||||||
action='store', dest='remote_exec',
|
action='store', dest='remote_exec',
|
||||||
|
@ -126,15 +108,16 @@ def commandline():
|
||||||
parser['config'].set_defaults(func=cdist.config.Config.commandline)
|
parser['config'].set_defaults(func=cdist.config.Config.commandline)
|
||||||
|
|
||||||
# Shell
|
# Shell
|
||||||
parser['shell'] = parser['sub'].add_parser('shell',
|
parser['shell'] = parser['sub'].add_parser(
|
||||||
parents=[parser['loglevel']])
|
'shell', parents=[parser['loglevel']])
|
||||||
parser['shell'].add_argument('-s', '--shell',
|
parser['shell'].add_argument(
|
||||||
|
'-s', '--shell',
|
||||||
help='Select shell to use, defaults to current shell')
|
help='Select shell to use, defaults to current shell')
|
||||||
parser['shell'].set_defaults(func=cdist.shell.Shell.commandline)
|
parser['shell'].set_defaults(func=cdist.shell.Shell.commandline)
|
||||||
|
|
||||||
|
|
||||||
for p in parser:
|
for p in parser:
|
||||||
parser[p].epilog = "Get cdist at http://www.nico.schottelius.org/software/cdist/"
|
parser[p].epilog = (
|
||||||
|
"Get cdist at http://www.nico.schottelius.org/software/cdist/")
|
||||||
|
|
||||||
args = parser['main'].parse_args(sys.argv[1:])
|
args = parser['main'].parse_args(sys.argv[1:])
|
||||||
|
|
||||||
|
@ -143,26 +126,6 @@ def commandline():
|
||||||
logging.root.setLevel(logging.INFO)
|
logging.root.setLevel(logging.INFO)
|
||||||
if args.debug:
|
if args.debug:
|
||||||
logging.root.setLevel(logging.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")
|
|
||||||
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
|
|
||||||
|
|
||||||
if args.command == 'config':
|
|
||||||
if args.manifest == '-' and args.hostfile == '-':
|
|
||||||
print('cdist config: error: cannot read both, manifest and host file, from stdin')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
log.debug(args)
|
log.debug(args)
|
||||||
log.info("version %s" % cdist.VERSION)
|
log.info("version %s" % cdist.VERSION)
|
||||||
|
@ -194,7 +157,6 @@ if __name__ == "__main__":
|
||||||
' is required on the source host.', file=sys.stderr)
|
' is required on the source host.', file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
exit_code = 0
|
exit_code = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in a new issue