Add -f option for reading hosts from file or stdin.

This commit is contained in:
Darko Poljak 2016-05-22 09:22:39 +02:00
parent 091ddac384
commit 4fce4a631c
3 changed files with 58 additions and 9 deletions

View file

@ -53,6 +53,21 @@ class Config(object):
self.local.create_files_dirs() self.local.create_files_dirs()
self.remote.create_files_dirs() self.remote.create_files_dirs()
@staticmethod
def hosts(source):
"""Yield hosts from source.
Source can be a sequence or filename (stdin if \'-\').
In case of filename each line represents one host.
"""
if isinstance(source, str):
import fileinput
for host in fileinput.input(files=(source)):
yield host.strip() # remove leading and trailing whitespace
else:
for host in source:
yield host
@classmethod @classmethod
def commandline(cls, args): def commandline(cls, args):
"""Configure remote system""" """Configure remote system"""
@ -60,6 +75,12 @@ class Config(object):
# FIXME: Refactor relict - remove later # FIXME: Refactor relict - remove later
log = logging.getLogger("cdist") log = logging.getLogger("cdist")
if args.manifest == '-' and args.hostfile == '-':
raise cdist.Error("Cannot read both, manifest and host file, from stdin")
# if no host source is specified then read hosts from stdin
if not (args.hostfile or args.host):
args.hostfile = '-'
initial_manifest_tempfile = None initial_manifest_tempfile = None
if args.manifest == '-': if args.manifest == '-':
@ -79,8 +100,15 @@ class Config(object):
process = {} process = {}
failed_hosts = [] failed_hosts = []
time_start = time.time() time_start = time.time()
hostcnt = 0
if args.host:
host_source = args.host
else:
host_source = args.hostfile
for host in args.host: for host in cls.hosts(host_source):
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(target=cls.onehost, args=(host, args, True)) process[host] = multiprocessing.Process(target=cls.onehost, args=(host, args, True))
@ -101,7 +129,7 @@ class Config(object):
failed_hosts.append(host) failed_hosts.append(host)
time_end = time.time() time_end = time.time()
log.info("Total processing time for %s host(s): %s", len(args.host), log.info("Total processing time for %s host(s): %s", hostcnt,
(time_end - time_start)) (time_end - time_start))
if len(failed_hosts) > 0: if len(failed_hosts) > 0:

View file

@ -14,7 +14,7 @@ cdist [-h] [-d] [-v] [-V] {banner,config,shell} ...
cdist banner [-h] [-d] [-v] cdist banner [-h] [-d] [-v]
cdist config [-h] [-d] [-V] [-c CONF_DIR] [-i MANIFEST] [-p] [-s] host [host ...] cdist config [-h] [-d] [-V] [-c CONF_DIR] [-f HOSTFILE] [-i MANIFEST] [-p] [-s] [host [host ...]]
cdist shell [-h] [-d] [-v] [-s SHELL] cdist shell [-h] [-d] [-v] [-s SHELL]
@ -63,6 +63,11 @@ Configure one or more hosts
--conf-dir argument have higher precedence over those set through the --conf-dir argument have higher precedence over those set through the
environment variable. environment variable.
-f HOSTFILE, --file HOSTFILE::
Read 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.
-i MANIFEST, --initial-manifest MANIFEST:: -i MANIFEST, --initial-manifest MANIFEST::
Path to a cdist manifest or - to read from stdin Path to a cdist manifest or - to read from stdin
@ -105,6 +110,9 @@ EXAMPLES
--remote-copy /path/to/my/remote/copy \ --remote-copy /path/to/my/remote/copy \
-p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch
# Configure hosts in parallel by reading hosts from file loadbalancers
% cdist config -f loadbalancers
# Display banner # Display banner
cdist banner cdist banner

View file

@ -67,12 +67,14 @@ def commandline():
action='store_true', default=False) action='store_true', default=False)
# Main subcommand parser # Main subcommand parser
parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION, parser['main'] = argparse.ArgumentParser(description='cdist '
+ cdist.VERSION,
parents=[parser['loglevel']]) parents=[parser['loglevel']])
parser['main'].add_argument('-V', '--version', parser['main'].add_argument('-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(title="Commands",
dest="command")
# Banner # Banner
parser['banner'] = parser['sub'].add_parser('banner', parser['banner'] = parser['sub'].add_parser('banner',
@ -82,11 +84,16 @@ def commandline():
# Config # Config
parser['config'] = parser['sub'].add_parser('config', parser['config'] = parser['sub'].add_parser('config',
parents=[parser['loglevel']]) parents=[parser['loglevel']])
parser['config'].add_argument('host', nargs='+', parser['config'].add_argument('host', nargs='*',
help='one or more hosts to operate on') help='one or more hosts to operate on')
parser['config'].add_argument('-c', '--conf-dir', parser['config'].add_argument('-c', '--conf-dir',
help='Add configuration directory (can be repeated, last one wins)', help=('Add configuration directory (can be repeated, '
action='append') 'last one wins)'), action='append')
parser['config'].add_argument('-f', '--file',
help=('Read 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', 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)
@ -108,7 +115,8 @@ def commandline():
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 (should behave like ssh)', help=('Command to use for remote execution '
'(should behave like ssh)'),
action='store', dest='remote_exec', action='store', dest='remote_exec',
default=os.environ.get('CDIST_REMOTE_EXEC')) default=os.environ.get('CDIST_REMOTE_EXEC'))
parser['config'].set_defaults(func=cdist.config.Config.commandline) parser['config'].set_defaults(func=cdist.config.Config.commandline)
@ -147,6 +155,11 @@ def commandline():
if args_dict['remote_copy'] is None: if args_dict['remote_copy'] is None:
args.remote_copy = cdist.REMOTE_COPY + mux_opts 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)