forked from ungleich-public/cdist
6f28fc2db2
ssh ControlPath socket file needs to be unique for each host. To avoid using ssh ControlPath option placeholders move socket file to host's temp directory. Since each host has unique temp directory then, although file name for socket file is fixed, its path is unique.
187 lines
6.4 KiB
Python
Executable file
187 lines
6.4 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# -*- 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.
|
|
#
|
|
# 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 <http://www.gnu.org/licenses/>.
|
|
#
|
|
#
|
|
|
|
|
|
def commandline():
|
|
"""Parse command line"""
|
|
import argparse
|
|
|
|
import cdist.banner
|
|
import cdist.config
|
|
import cdist.shell
|
|
import shutil
|
|
import os
|
|
|
|
# Construct parser others can reuse
|
|
parser = {}
|
|
# Options _all_ parsers have in common
|
|
parser['loglevel'] = argparse.ArgumentParser(add_help=False)
|
|
parser['loglevel'].add_argument(
|
|
'-d', '--debug', help='Set log level to debug',
|
|
action='store_true', default=False)
|
|
parser['loglevel'].add_argument(
|
|
'-v', '--verbose', help='Set log level to info, be more verbose',
|
|
action='store_true', default=False)
|
|
|
|
# Main subcommand parser
|
|
parser['main'] = argparse.ArgumentParser(
|
|
description='cdist ' + cdist.VERSION, parents=[parser['loglevel']])
|
|
parser['main'].add_argument(
|
|
'-V', '--version', help='Show version', action='version',
|
|
version='%(prog)s ' + cdist.VERSION)
|
|
parser['sub'] = parser['main'].add_subparsers(
|
|
title="Commands", dest="command")
|
|
|
|
# Banner
|
|
parser['banner'] = parser['sub'].add_parser(
|
|
'banner', parents=[parser['loglevel']])
|
|
parser['banner'].set_defaults(func=cdist.banner.banner)
|
|
|
|
# Config
|
|
parser['config'] = parser['sub'].add_parser(
|
|
'config', parents=[parser['loglevel']])
|
|
parser['config'].add_argument(
|
|
'host', nargs='*', help='host(s) to operate on')
|
|
parser['config'].add_argument(
|
|
'-c', '--conf-dir',
|
|
help=('Add configuration directory (can be repeated, '
|
|
'last one wins)'), action='append')
|
|
parser['config'].add_argument(
|
|
'-f', '--file',
|
|
help=('Read additional hosts to operate on from specified file '
|
|
'or from stdin if \'-\' (each host on separate line). '
|
|
'If no host or host file is specified then, by default, '
|
|
'read hosts from stdin.'),
|
|
dest='hostfile', required=False)
|
|
parser['config'].add_argument(
|
|
'-i', '--initial-manifest',
|
|
help='Path to a cdist manifest or \'-\' to read from stdin.',
|
|
dest='manifest', required=False)
|
|
parser['config'].add_argument(
|
|
'-n', '--dry-run',
|
|
help='Do not execute code', action='store_true')
|
|
parser['config'].add_argument(
|
|
'-o', '--out-dir',
|
|
help='Directory to save cdist output in', dest="out_path")
|
|
parser['config'].add_argument(
|
|
'-p', '--parallel',
|
|
help='Operate on multiple hosts in parallel',
|
|
action='store_true', dest='parallel')
|
|
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=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=os.environ.get('CDIST_REMOTE_EXEC'))
|
|
parser['config'].set_defaults(func=cdist.config.Config.commandline)
|
|
|
|
# Shell
|
|
parser['shell'] = parser['sub'].add_parser(
|
|
'shell', parents=[parser['loglevel']])
|
|
parser['shell'].add_argument(
|
|
'-s', '--shell',
|
|
help='Select shell to use, defaults to current shell')
|
|
parser['shell'].set_defaults(func=cdist.shell.Shell.commandline)
|
|
|
|
for p in parser:
|
|
parser[p].epilog = (
|
|
"Get cdist at http://www.nico.schottelius.org/software/cdist/")
|
|
|
|
args = parser['main'].parse_args(sys.argv[1:])
|
|
|
|
# Loglevels are handled globally in here and debug wins over verbose
|
|
if args.verbose:
|
|
logging.root.setLevel(logging.INFO)
|
|
if args.debug:
|
|
logging.root.setLevel(logging.DEBUG)
|
|
|
|
log.debug(args)
|
|
log.info("version %s" % cdist.VERSION)
|
|
|
|
# Work around python 3.3 bug:
|
|
# http://bugs.python.org/issue16308
|
|
# http://bugs.python.org/issue9253
|
|
|
|
# FIXME: catching AttributeError also hides
|
|
# real problems.. try a different way
|
|
|
|
# FIXME: we always print main help, not
|
|
# the help of the actual parser being used!
|
|
try:
|
|
getattr(args, "func")
|
|
except AttributeError:
|
|
parser['main'].print_help()
|
|
sys.exit(0)
|
|
|
|
args.func(args)
|
|
|
|
if __name__ == "__main__":
|
|
# Sys is needed for sys.exit()
|
|
import sys
|
|
|
|
cdistpythonversion = '3.2'
|
|
if sys.version < cdistpythonversion:
|
|
print('Python >= ' + cdistpythonversion +
|
|
' is required on the source host.', file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
exit_code = 0
|
|
|
|
try:
|
|
import logging
|
|
import os
|
|
import re
|
|
import cdist
|
|
import cdist.log
|
|
|
|
logging.setLoggerClass(cdist.log.Log)
|
|
logging.basicConfig(format='%(levelname)s: %(message)s')
|
|
log = logging.getLogger("cdist")
|
|
|
|
if re.match("__", os.path.basename(sys.argv[0])):
|
|
import cdist.emulator
|
|
emulator = cdist.emulator.Emulator(sys.argv)
|
|
emulator.run()
|
|
else:
|
|
commandline()
|
|
|
|
except KeyboardInterrupt:
|
|
exit_code = 2
|
|
|
|
except cdist.Error as e:
|
|
log.error(e)
|
|
exit_code = 1
|
|
|
|
sys.exit(exit_code)
|