Merge remote-tracking branch 'ungleich/master' into ssh-mux-sigpipe
This commit is contained in:
commit
060ddc2a17
32 changed files with 1831 additions and 50 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -11,6 +11,9 @@ docs/src/cdist-reference.rst
|
|||
# Ignore cdist cache for version control
|
||||
/cache/
|
||||
|
||||
# Ignore inventory basedir
|
||||
cdist/inventory/
|
||||
|
||||
# Python: cache, distutils, distribution in general
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
|
|
@ -7,10 +7,10 @@ import collections
|
|||
|
||||
|
||||
# set of beta sub-commands
|
||||
BETA_COMMANDS = set(('install', ))
|
||||
BETA_COMMANDS = set(('install', 'inventory', ))
|
||||
# set of beta arguments for sub-commands
|
||||
BETA_ARGS = {
|
||||
'config': set(('jobs', )),
|
||||
'config': set(('jobs', 'tag', 'all_tagged_hosts', )),
|
||||
}
|
||||
EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/"
|
||||
# Parser others can reuse
|
||||
|
@ -121,6 +121,17 @@ def get_parsers():
|
|||
'banner', parents=[parser['loglevel']])
|
||||
parser['banner'].set_defaults(func=cdist.banner.banner)
|
||||
|
||||
parser['inventory_common'] = argparse.ArgumentParser(add_help=False)
|
||||
parser['inventory_common'].add_argument(
|
||||
'-I', '--inventory',
|
||||
help=('Use specified custom inventory directory. '
|
||||
'Inventory directory is set up by the following rules: '
|
||||
'if this argument is set then specified directory is used, '
|
||||
'if CDIST_INVENTORY_DIR env var is set then its value is '
|
||||
'used, if HOME env var is set then ~/.cdist/inventory is '
|
||||
'used, otherwise distribution inventory directory is used.'),
|
||||
dest="inventory_dir", required=False)
|
||||
|
||||
# Config
|
||||
parser['config_main'] = argparse.ArgumentParser(add_help=False)
|
||||
parser['config_main'].add_argument(
|
||||
|
@ -156,6 +167,10 @@ def get_parsers():
|
|||
# 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_main'].add_argument(
|
||||
'-r', '--remote-out-dir',
|
||||
help='Directory to save cdist output in on the target host',
|
||||
dest="remote_out_path")
|
||||
parser['config_main'].add_argument(
|
||||
'--remote-copy',
|
||||
help='Command to use for remote copy (should behave like scp)',
|
||||
|
@ -170,6 +185,15 @@ def get_parsers():
|
|||
|
||||
# Config
|
||||
parser['config_args'] = argparse.ArgumentParser(add_help=False)
|
||||
parser['config_args'].add_argument(
|
||||
'-A', '--all-tagged',
|
||||
help=('use all hosts present in tags db'),
|
||||
action="store_true", dest="all_tagged_hosts", default=False)
|
||||
parser['config_args'].add_argument(
|
||||
'-a', '--all',
|
||||
help=('list hosts that have all specified tags, '
|
||||
'if -t/--tag is specified'),
|
||||
action="store_true", dest="has_all_tags", default=False)
|
||||
parser['config_args'].add_argument(
|
||||
'host', nargs='*', help='host(s) to operate on')
|
||||
parser['config_args'].add_argument(
|
||||
|
@ -183,17 +207,19 @@ def get_parsers():
|
|||
'-p', '--parallel',
|
||||
help='operate on multiple hosts in parallel',
|
||||
action='store_true', dest='parallel')
|
||||
parser['config_args'].add_argument(
|
||||
'-r', '--remote-out-dir',
|
||||
help='Directory to save cdist output in on the target host',
|
||||
dest="remote_out_path")
|
||||
parser['config_args'].add_argument(
|
||||
'-s', '--sequential',
|
||||
help='operate on multiple hosts sequentially (default)',
|
||||
action='store_false', dest='parallel')
|
||||
parser['config_args'].add_argument(
|
||||
'-t', '--tag',
|
||||
help=('host is specified by tag, not hostname/address; '
|
||||
'list all hosts that contain any of specified tags'),
|
||||
dest='tag', required=False, action="store_true", default=False)
|
||||
parser['config'] = parser['sub'].add_parser(
|
||||
'config', parents=[parser['loglevel'], parser['beta'],
|
||||
parser['config_main'],
|
||||
parser['inventory_common'],
|
||||
parser['config_args']])
|
||||
parser['config'].set_defaults(func=cdist.config.Config.commandline)
|
||||
|
||||
|
@ -202,6 +228,134 @@ def get_parsers():
|
|||
parents=[parser['config']])
|
||||
parser['install'].set_defaults(func=cdist.install.Install.commandline)
|
||||
|
||||
# Inventory
|
||||
parser['inventory'] = parser['sub'].add_parser(
|
||||
'inventory', parents=[parser['loglevel'], parser['beta'],
|
||||
parser['inventory_common']])
|
||||
parser['invsub'] = parser['inventory'].add_subparsers(
|
||||
title="Inventory commands", dest="subcommand")
|
||||
|
||||
parser['add-host'] = parser['invsub'].add_parser(
|
||||
'add-host', parents=[parser['loglevel'], parser['beta'],
|
||||
parser['inventory_common']])
|
||||
parser['add-host'].add_argument(
|
||||
'host', nargs='*', help='host(s) to add')
|
||||
parser['add-host'].add_argument(
|
||||
'-f', '--file',
|
||||
help=('Read additional hosts to add from specified file '
|
||||
'or from stdin if \'-\' (each host on separate line). '
|
||||
'If no host or host file is specified then, by default, '
|
||||
'read from stdin.'),
|
||||
dest='hostfile', required=False)
|
||||
|
||||
parser['add-tag'] = parser['invsub'].add_parser(
|
||||
'add-tag', parents=[parser['loglevel'], parser['beta'],
|
||||
parser['inventory_common']])
|
||||
parser['add-tag'].add_argument(
|
||||
'host', nargs='*',
|
||||
help='list of host(s) for which tags are added')
|
||||
parser['add-tag'].add_argument(
|
||||
'-f', '--file',
|
||||
help=('Read additional hosts to add tags from specified file '
|
||||
'or from stdin if \'-\' (each host on separate line). '
|
||||
'If no host or host file is specified then, by default, '
|
||||
'read from stdin. If no tags/tagfile nor hosts/hostfile'
|
||||
' are specified then tags are read from stdin and are'
|
||||
' added to all hosts.'),
|
||||
dest='hostfile', required=False)
|
||||
parser['add-tag'].add_argument(
|
||||
'-T', '--tag-file',
|
||||
help=('Read additional tags to add from specified file '
|
||||
'or from stdin if \'-\' (each tag on separate line). '
|
||||
'If no tag or tag file is specified then, by default, '
|
||||
'read from stdin. If no tags/tagfile nor hosts/hostfile'
|
||||
' are specified then tags are read from stdin and are'
|
||||
' added to all hosts.'),
|
||||
dest='tagfile', required=False)
|
||||
parser['add-tag'].add_argument(
|
||||
'-t', '--taglist',
|
||||
help=("Tag list to be added for specified host(s), comma separated"
|
||||
" values"),
|
||||
dest="taglist", required=False)
|
||||
|
||||
parser['del-host'] = parser['invsub'].add_parser(
|
||||
'del-host', parents=[parser['loglevel'], parser['beta'],
|
||||
parser['inventory_common']])
|
||||
parser['del-host'].add_argument(
|
||||
'host', nargs='*', help='host(s) to delete')
|
||||
parser['del-host'].add_argument(
|
||||
'-a', '--all', help=('Delete all hosts'),
|
||||
dest='all', required=False, action="store_true", default=False)
|
||||
parser['del-host'].add_argument(
|
||||
'-f', '--file',
|
||||
help=('Read additional hosts to delete from specified file '
|
||||
'or from stdin if \'-\' (each host on separate line). '
|
||||
'If no host or host file is specified then, by default, '
|
||||
'read from stdin.'),
|
||||
dest='hostfile', required=False)
|
||||
|
||||
parser['del-tag'] = parser['invsub'].add_parser(
|
||||
'del-tag', parents=[parser['loglevel'], parser['beta'],
|
||||
parser['inventory_common']])
|
||||
parser['del-tag'].add_argument(
|
||||
'host', nargs='*',
|
||||
help='list of host(s) for which tags are deleted')
|
||||
parser['del-tag'].add_argument(
|
||||
'-a', '--all',
|
||||
help=('Delete all tags for specified host(s)'),
|
||||
dest='all', required=False, action="store_true", default=False)
|
||||
parser['del-tag'].add_argument(
|
||||
'-f', '--file',
|
||||
help=('Read additional hosts to delete tags for from specified '
|
||||
'file or from stdin if \'-\' (each host on separate line). '
|
||||
'If no host or host file is specified then, by default, '
|
||||
'read from stdin. If no tags/tagfile nor hosts/hostfile'
|
||||
' are specified then tags are read from stdin and are'
|
||||
' deleted from all hosts.'),
|
||||
dest='hostfile', required=False)
|
||||
parser['del-tag'].add_argument(
|
||||
'-T', '--tag-file',
|
||||
help=('Read additional tags from specified file '
|
||||
'or from stdin if \'-\' (each tag on separate line). '
|
||||
'If no tag or tag file is specified then, by default, '
|
||||
'read from stdin. If no tags/tagfile nor'
|
||||
' hosts/hostfile are specified then tags are read from'
|
||||
' stdin and are added to all hosts.'),
|
||||
dest='tagfile', required=False)
|
||||
parser['del-tag'].add_argument(
|
||||
'-t', '--taglist',
|
||||
help=("Tag list to be deleted for specified host(s), "
|
||||
"comma separated values"),
|
||||
dest="taglist", required=False)
|
||||
|
||||
parser['list'] = parser['invsub'].add_parser(
|
||||
'list', parents=[parser['loglevel'], parser['beta'],
|
||||
parser['inventory_common']])
|
||||
parser['list'].add_argument(
|
||||
'host', nargs='*', help='host(s) to list')
|
||||
parser['list'].add_argument(
|
||||
'-a', '--all',
|
||||
help=('list hosts that have all specified tags, '
|
||||
'if -t/--tag is specified'),
|
||||
action="store_true", dest="has_all_tags", default=False)
|
||||
parser['list'].add_argument(
|
||||
'-f', '--file',
|
||||
help=('Read additional hosts to list from specified file '
|
||||
'or from stdin if \'-\' (each host on separate line). '
|
||||
'If no host or host file is specified then, by default, '
|
||||
'list all.'), dest='hostfile', required=False)
|
||||
parser['list'].add_argument(
|
||||
'-H', '--host-only', help=('Suppress tags listing'),
|
||||
action="store_true", dest="list_only_host", default=False)
|
||||
parser['list'].add_argument(
|
||||
'-t', '--tag',
|
||||
help=('host is specified by tag, not hostname/address; '
|
||||
'list all hosts that contain any of specified tags'),
|
||||
action="store_true", default=False)
|
||||
|
||||
parser['inventory'].set_defaults(
|
||||
func=cdist.inventory.Inventory.commandline)
|
||||
|
||||
# Shell
|
||||
parser['shell'] = parser['sub'].add_parser(
|
||||
'shell', parents=[parser['loglevel']])
|
||||
|
|
|
@ -17,9 +17,9 @@ REQUIRED PARAMETERS
|
|||
uri
|
||||
The uri from which to fetch the tarball.
|
||||
Can be anything understood by curl, e.g:
|
||||
| http://path/to/stage.tgz
|
||||
| tftp:///path/to/stage.tgz
|
||||
| file:///local/path/stage.tgz
|
||||
| http://path/to/stage.tgz
|
||||
| tftp:///path/to/stage.tgz
|
||||
| file:///local/path/stage.tgz
|
||||
|
||||
|
||||
OPTIONAL PARAMETERS
|
||||
|
|
21
cdist/conf/type/__timezone/explorer/timezone_is
Executable file
21
cdist/conf/type/__timezone/explorer/timezone_is
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# 2017 Ander Punnar (cdist at kvlt.ee)
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
[ -f /etc/timezone ] && cat /etc/timezone
|
|
@ -20,11 +20,16 @@
|
|||
#
|
||||
# This type allows to configure the desired localtime timezone.
|
||||
|
||||
timezone="$__object_id"
|
||||
timezone_is=$(cat "$__object/explorer/timezone_is")
|
||||
timezone_should="$__object_id"
|
||||
os=$(cat "$__global/explorer/os")
|
||||
|
||||
if [ "$timezone_is" = "$timezone_should" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case "$os" in
|
||||
ubuntu|debian|devuan)
|
||||
echo "echo \"$timezone\" > /etc/timezone"
|
||||
echo "echo \"$timezone_should\" > /etc/timezone"
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -38,6 +38,9 @@ import cdist.hostsource
|
|||
|
||||
import cdist.exec.local
|
||||
import cdist.exec.remote
|
||||
|
||||
from cdist import inventory
|
||||
|
||||
import cdist.util.ipaddr as ipaddr
|
||||
|
||||
from cdist import core
|
||||
|
@ -141,11 +144,42 @@ class Config(object):
|
|||
base_root_path = cls.create_base_root_path(args.out_path)
|
||||
|
||||
hostcnt = 0
|
||||
for host in itertools.chain(cls.hosts(args.host),
|
||||
cls.hosts(args.hostfile)):
|
||||
|
||||
if args.tag or args.all_tagged_hosts:
|
||||
inventory.determine_default_inventory_dir(args)
|
||||
if args.all_tagged_hosts:
|
||||
inv_list = inventory.InventoryList(
|
||||
hosts=None, istag=True, hostfile=None,
|
||||
db_basedir=args.inventory_dir)
|
||||
else:
|
||||
inv_list = inventory.InventoryList(
|
||||
hosts=args.host, istag=True, hostfile=args.hostfile,
|
||||
db_basedir=args.inventory_dir,
|
||||
has_all_tags=args.has_all_tags)
|
||||
it = inv_list.entries()
|
||||
else:
|
||||
it = itertools.chain(cls.hosts(args.host),
|
||||
cls.hosts(args.hostfile))
|
||||
for entry in it:
|
||||
if isinstance(entry, tuple):
|
||||
# if configuring by specified tags
|
||||
host = entry[0]
|
||||
host_tags = entry[1]
|
||||
else:
|
||||
# if configuring by host then check inventory for tags
|
||||
host = entry
|
||||
inventory.determine_default_inventory_dir(args)
|
||||
inv_list = inventory.InventoryList(
|
||||
hosts=(host,), db_basedir=args.inventory_dir)
|
||||
inv = tuple(inv_list.entries())
|
||||
if inv:
|
||||
# host is present in inventory and has tags
|
||||
host_tags = inv[0][1]
|
||||
else:
|
||||
# host is not present in inventory or has no tags
|
||||
host_tags = None
|
||||
host_base_path, hostdir = cls.create_host_base_dirs(
|
||||
host, base_root_path)
|
||||
|
||||
log.debug("Base root path for target host \"{}\" is \"{}\"".format(
|
||||
host, host_base_path))
|
||||
|
||||
|
@ -154,11 +188,12 @@ class Config(object):
|
|||
log.trace("Creating child process for %s", host)
|
||||
process[host] = multiprocessing.Process(
|
||||
target=cls.onehost,
|
||||
args=(host, host_base_path, hostdir, args, True))
|
||||
args=(host, host_tags, host_base_path, hostdir, args,
|
||||
True))
|
||||
process[host].start()
|
||||
else:
|
||||
try:
|
||||
cls.onehost(host, host_base_path, hostdir,
|
||||
cls.onehost(host, host_tags, host_base_path, hostdir,
|
||||
args, parallel=False)
|
||||
except cdist.Error as e:
|
||||
failed_hosts.append(host)
|
||||
|
@ -211,7 +246,8 @@ class Config(object):
|
|||
return (remote_exec, remote_copy, remote_cmds_cleanup, )
|
||||
|
||||
@classmethod
|
||||
def onehost(cls, host, host_base_path, host_dir_name, args, parallel):
|
||||
def onehost(cls, host, host_tags, host_base_path, host_dir_name, args,
|
||||
parallel):
|
||||
"""Configure ONE system"""
|
||||
|
||||
log = logging.getLogger(host)
|
||||
|
@ -229,6 +265,7 @@ class Config(object):
|
|||
|
||||
local = cdist.exec.local.Local(
|
||||
target_host=target_host,
|
||||
target_host_tags=host_tags,
|
||||
base_root_path=host_base_path,
|
||||
host_dir_name=host_dir_name,
|
||||
initial_manifest=args.manifest,
|
||||
|
@ -445,7 +482,7 @@ class Config(object):
|
|||
for chunk in cargo:
|
||||
for obj in chunk:
|
||||
if (obj.cdist_type == cdist_object.cdist_type and
|
||||
cdist_object.cdist_type.is_nonparallel):
|
||||
cdist_object.cdist_type.is_nonparallel):
|
||||
break
|
||||
else:
|
||||
chunk.append(cdist_object)
|
||||
|
|
|
@ -56,6 +56,7 @@ gencode-local
|
|||
__object_fq: full qualified object id, iow: $type.name + / + object_id
|
||||
__type: full qualified path to the type's dir
|
||||
__files: full qualified path to the files dir
|
||||
__target_host_tags: comma spearated list of host tags
|
||||
|
||||
returns: string containing the generated code or None
|
||||
|
||||
|
@ -74,6 +75,7 @@ gencode-remote
|
|||
__object_fq: full qualified object id, iow: $type.name + / + object_id
|
||||
__type: full qualified path to the type's dir
|
||||
__files: full qualified path to the files dir
|
||||
__target_host_tags: comma spearated list of host tags
|
||||
|
||||
returns: string containing the generated code or None
|
||||
|
||||
|
@ -106,6 +108,7 @@ class Code(object):
|
|||
'__target_fqdn': self.target_host[2],
|
||||
'__global': self.local.base_path,
|
||||
'__files': self.local.files_path,
|
||||
'__target_host_tags': self.local.target_host_tags,
|
||||
}
|
||||
|
||||
def _run_gencode(self, cdist_object, which):
|
||||
|
|
|
@ -77,6 +77,7 @@ class Explorer(object):
|
|||
'__target_hostname': self.target_host[1],
|
||||
'__target_fqdn': self.target_host[2],
|
||||
'__explorer': self.remote.global_explorer_path,
|
||||
'__target_host_tags': self.local.target_host_tags,
|
||||
}
|
||||
self._type_explorers_transferred = []
|
||||
self.jobs = jobs
|
||||
|
|
|
@ -42,6 +42,7 @@ common:
|
|||
types are defined for use in type emulator
|
||||
== local.type_path
|
||||
__files: full qualified path to the files dir
|
||||
__target_host_tags: comma spearated list of host tags
|
||||
|
||||
initial manifest is:
|
||||
script: full qualified path to the initial manifest
|
||||
|
@ -109,6 +110,7 @@ class Manifest(object):
|
|||
'__target_hostname': self.target_host[1],
|
||||
'__target_fqdn': self.target_host[2],
|
||||
'__files': self.local.files_path,
|
||||
'__target_host_tags': self.local.target_host_tags,
|
||||
}
|
||||
|
||||
if self.log.getEffectiveLevel() == logging.DEBUG:
|
||||
|
|
|
@ -49,6 +49,7 @@ class Local(object):
|
|||
"""
|
||||
def __init__(self,
|
||||
target_host,
|
||||
target_host_tags,
|
||||
base_root_path,
|
||||
host_dir_name,
|
||||
exec_path=sys.argv[0],
|
||||
|
@ -58,6 +59,10 @@ class Local(object):
|
|||
quiet_mode=False):
|
||||
|
||||
self.target_host = target_host
|
||||
if target_host_tags is None:
|
||||
self.target_host_tags = ""
|
||||
else:
|
||||
self.target_host_tags = ",".join(target_host_tags)
|
||||
self.hostdir = host_dir_name
|
||||
self.base_path = os.path.join(base_root_path, "data")
|
||||
|
||||
|
|
390
cdist/inventory.py
Normal file
390
cdist/inventory.py
Normal file
|
@ -0,0 +1,390 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
#
|
||||
|
||||
import cdist
|
||||
import logging
|
||||
import os
|
||||
import os.path
|
||||
import itertools
|
||||
import sys
|
||||
from cdist.hostsource import hostfile_process_line
|
||||
|
||||
DIST_INVENTORY_DB_NAME = "inventory"
|
||||
|
||||
dist_inventory_db = os.path.abspath(os.path.join(
|
||||
os.path.dirname(cdist.__file__), DIST_INVENTORY_DB_NAME))
|
||||
|
||||
|
||||
def determine_default_inventory_dir(args):
|
||||
# The order of inventory dir setting by decreasing priority
|
||||
# 1. inventory_dir argument
|
||||
# 2. CDIST_INVENTORY_DIR env var if set
|
||||
# 3. ~/.cdist/inventory if HOME env var is set
|
||||
# 4. distribution inventory directory
|
||||
if not args.inventory_dir:
|
||||
if 'CDIST_INVENTORY_DIR' in os.environ:
|
||||
args.inventory_dir = os.environ['CDIST_INVENTORY_DIR']
|
||||
else:
|
||||
home = cdist.home_dir()
|
||||
if home:
|
||||
args.inventory_dir = os.path.join(home, DIST_INVENTORY_DB_NAME)
|
||||
else:
|
||||
args.inventory_dir = dist_inventory_db
|
||||
|
||||
|
||||
def contains_all(big, little):
|
||||
"""Return True if big contains all elements from little,
|
||||
False otherwise.
|
||||
"""
|
||||
return set(little).issubset(set(big))
|
||||
|
||||
|
||||
def contains_any(big, little):
|
||||
"""Return True if big contains any element from little,
|
||||
False otherwise.
|
||||
"""
|
||||
for x in little:
|
||||
if x in big:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def check_always_true(x, y):
|
||||
return True
|
||||
|
||||
|
||||
def rstrip_nl(s):
|
||||
'''str.rstrip "\n" from s'''
|
||||
return str.rstrip(s, "\n")
|
||||
|
||||
|
||||
class Inventory(object):
|
||||
"""Inventory main class"""
|
||||
|
||||
def __init__(self, db_basedir=dist_inventory_db):
|
||||
self.db_basedir = db_basedir
|
||||
self.log = logging.getLogger("inventory")
|
||||
self.init_db()
|
||||
|
||||
def init_db(self):
|
||||
self.log.debug("Init db: {}".format(self.db_basedir))
|
||||
if not os.path.exists(self.db_basedir):
|
||||
os.makedirs(self.db_basedir, exist_ok=True)
|
||||
elif not os.path.isdir(self.db_basedir):
|
||||
raise cdist.Error(("Invalid inventory db basedir \'{}\',"
|
||||
" must be a directory").format(self.db_basedir))
|
||||
|
||||
@staticmethod
|
||||
def strlist_to_list(slist):
|
||||
if slist:
|
||||
result = [x for x in slist.split(',') if x]
|
||||
else:
|
||||
result = []
|
||||
return result
|
||||
|
||||
def _input_values(self, source):
|
||||
"""Yield input values from source.
|
||||
Source can be a sequence or filename (stdin if '-').
|
||||
In case of filename each line represents one input value.
|
||||
"""
|
||||
if isinstance(source, str):
|
||||
import fileinput
|
||||
try:
|
||||
with fileinput.FileInput(files=(source)) as f:
|
||||
for x in f:
|
||||
result = hostfile_process_line(x, strip_func=rstrip_nl)
|
||||
if result:
|
||||
yield result
|
||||
except (IOError, OSError) as e:
|
||||
raise cdist.Error("Error reading from \'{}\'".format(
|
||||
source))
|
||||
else:
|
||||
if source:
|
||||
for x in source:
|
||||
if x:
|
||||
yield x
|
||||
|
||||
def _host_path(self, host):
|
||||
hostpath = os.path.join(self.db_basedir, host)
|
||||
return hostpath
|
||||
|
||||
def _all_hosts(self):
|
||||
return os.listdir(self.db_basedir)
|
||||
|
||||
def _check_host(self, hostpath):
|
||||
if not os.path.exists(hostpath):
|
||||
return False
|
||||
else:
|
||||
if not os.path.isfile(hostpath):
|
||||
raise cdist.Error(("Host path \'{}\' exists, but is not"
|
||||
" a valid file").format(hostpath))
|
||||
return True
|
||||
|
||||
def _read_host_tags(self, hostpath):
|
||||
result = set()
|
||||
with open(hostpath, "rt") as f:
|
||||
for tag in f:
|
||||
tag = tag.rstrip("\n")
|
||||
if tag:
|
||||
result.add(tag)
|
||||
return result
|
||||
|
||||
def _get_host_tags(self, host):
|
||||
hostpath = self._host_path(host)
|
||||
if self._check_host(hostpath):
|
||||
return self._read_host_tags(hostpath)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _write_host_tags(self, host, tags):
|
||||
hostpath = self._host_path(host)
|
||||
if self._check_host(hostpath):
|
||||
with open(hostpath, "wt") as f:
|
||||
for tag in tags:
|
||||
f.write("{}\n".format(tag))
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def commandline(cls, args):
|
||||
"""Manipulate inventory db"""
|
||||
log = logging.getLogger("cdist")
|
||||
if 'taglist' in args:
|
||||
args.taglist = cls.strlist_to_list(args.taglist)
|
||||
determine_default_inventory_dir(args)
|
||||
|
||||
log.info("Using inventory: {}".format(args.inventory_dir))
|
||||
log.debug("Inventory args: {}".format(vars(args)))
|
||||
log.debug("Inventory command: {}".format(args.subcommand))
|
||||
|
||||
if args.subcommand == "list":
|
||||
c = InventoryList(hosts=args.host, istag=args.tag,
|
||||
hostfile=args.hostfile,
|
||||
db_basedir=args.inventory_dir,
|
||||
list_only_host=args.list_only_host,
|
||||
has_all_tags=args.has_all_tags)
|
||||
elif args.subcommand == "add-host":
|
||||
c = InventoryHost(hosts=args.host, hostfile=args.hostfile,
|
||||
db_basedir=args.inventory_dir)
|
||||
elif args.subcommand == "del-host":
|
||||
c = InventoryHost(hosts=args.host, hostfile=args.hostfile,
|
||||
all=args.all, db_basedir=args.inventory_dir,
|
||||
action="del")
|
||||
elif args.subcommand == "add-tag":
|
||||
c = InventoryTag(hosts=args.host, tags=args.taglist,
|
||||
hostfile=args.hostfile, tagfile=args.tagfile,
|
||||
db_basedir=args.inventory_dir)
|
||||
elif args.subcommand == "del-tag":
|
||||
c = InventoryTag(hosts=args.host, tags=args.taglist,
|
||||
hostfile=args.hostfile, tagfile=args.tagfile,
|
||||
all=args.all, db_basedir=args.inventory_dir,
|
||||
action="del")
|
||||
else:
|
||||
raise cdist.Error("Unknown inventory command \'{}\'".format(
|
||||
args.subcommand))
|
||||
c.run()
|
||||
|
||||
|
||||
class InventoryList(Inventory):
|
||||
def __init__(self, hosts=None, istag=False, hostfile=None,
|
||||
list_only_host=False, has_all_tags=False,
|
||||
db_basedir=dist_inventory_db):
|
||||
super().__init__(db_basedir)
|
||||
self.hosts = hosts
|
||||
self.istag = istag
|
||||
self.hostfile = hostfile
|
||||
self.list_only_host = list_only_host
|
||||
self.has_all_tags = has_all_tags
|
||||
|
||||
def _print(self, host, tags):
|
||||
if self.list_only_host:
|
||||
print("{}".format(host))
|
||||
else:
|
||||
print("{} {}".format(host, ",".join(sorted(tags))))
|
||||
|
||||
def _do_list(self, it_tags, it_hosts, check_func):
|
||||
if (it_tags is not None):
|
||||
param_tags = set(it_tags)
|
||||
self.log.debug("param_tags: {}".format(param_tags))
|
||||
else:
|
||||
param_tags = set()
|
||||
for host in it_hosts:
|
||||
self.log.debug("host: {}".format(host))
|
||||
tags = self._get_host_tags(host)
|
||||
if tags is None:
|
||||
self.log.info("Host \'{}\' not found, skipped".format(host))
|
||||
continue
|
||||
self.log.debug("tags: {}".format(tags))
|
||||
if check_func(tags, param_tags):
|
||||
yield host, tags
|
||||
|
||||
def entries(self):
|
||||
if not self.hosts and not self.hostfile:
|
||||
self.log.info("Listing all hosts")
|
||||
it_hosts = self._all_hosts()
|
||||
it_tags = None
|
||||
check_func = check_always_true
|
||||
else:
|
||||
it = itertools.chain(self._input_values(self.hosts),
|
||||
self._input_values(self.hostfile))
|
||||
if self.istag:
|
||||
self.log.info("Listing by tag(s)")
|
||||
it_hosts = self._all_hosts()
|
||||
it_tags = it
|
||||
if self.has_all_tags:
|
||||
check_func = contains_all
|
||||
else:
|
||||
check_func = contains_any
|
||||
else:
|
||||
self.log.info("Listing by host(s)")
|
||||
it_hosts = it
|
||||
it_tags = None
|
||||
check_func = check_always_true
|
||||
for host, tags in self._do_list(it_tags, it_hosts, check_func):
|
||||
yield host, tags
|
||||
|
||||
def host_entries(self):
|
||||
for host, tags in self.entries():
|
||||
yield host
|
||||
|
||||
def run(self):
|
||||
for host, tags in self.entries():
|
||||
self._print(host, tags)
|
||||
|
||||
|
||||
class InventoryHost(Inventory):
|
||||
def __init__(self, hosts=None, hostfile=None,
|
||||
db_basedir=dist_inventory_db, all=False, action="add"):
|
||||
super().__init__(db_basedir)
|
||||
self.actions = ("add", "del")
|
||||
if action not in self.actions:
|
||||
raise cdist.Error("Invalid action \'{}\', valid actions are:"
|
||||
" {}\n".format(action, self.actions.keys()))
|
||||
self.action = action
|
||||
self.hosts = hosts
|
||||
self.hostfile = hostfile
|
||||
self.all = all
|
||||
|
||||
if not self.hosts and not self.hostfile:
|
||||
self.hostfile = "-"
|
||||
|
||||
def _new_hostpath(self, hostpath):
|
||||
# create empty file
|
||||
with open(hostpath, "w"):
|
||||
pass
|
||||
|
||||
def _action(self, host):
|
||||
if self.action == "add":
|
||||
self.log.info("Adding host \'{}\'".format(host))
|
||||
elif self.action == "del":
|
||||
self.log.info("Deleting host \'{}\'".format(host))
|
||||
hostpath = self._host_path(host)
|
||||
self.log.debug("hostpath: {}".format(hostpath))
|
||||
if self.action == "add" and not os.path.exists(hostpath):
|
||||
self._new_hostpath(hostpath)
|
||||
else:
|
||||
if not os.path.isfile(hostpath):
|
||||
raise cdist.Error(("Host path \'{}\' is"
|
||||
" not a valid file").format(hostpath))
|
||||
if self.action == "del":
|
||||
os.remove(hostpath)
|
||||
|
||||
def run(self):
|
||||
if self.action == "del" and self.all:
|
||||
self.log.debug("Doing for all hosts")
|
||||
it = self._all_hosts()
|
||||
else:
|
||||
self.log.debug("Doing for specified hosts")
|
||||
it = itertools.chain(self._input_values(self.hosts),
|
||||
self._input_values(self.hostfile))
|
||||
for host in it:
|
||||
self._action(host)
|
||||
|
||||
|
||||
class InventoryTag(Inventory):
|
||||
def __init__(self, hosts=None, tags=None, hostfile=None, tagfile=None,
|
||||
db_basedir=dist_inventory_db, all=False, action="add"):
|
||||
super().__init__(db_basedir)
|
||||
self.actions = ("add", "del")
|
||||
if action not in self.actions:
|
||||
raise cdist.Error("Invalid action \'{}\', valid actions are:"
|
||||
" {}\n".format(action, self.actions.keys()))
|
||||
self.action = action
|
||||
self.hosts = hosts
|
||||
self.tags = tags
|
||||
self.hostfile = hostfile
|
||||
self.tagfile = tagfile
|
||||
self.all = all
|
||||
|
||||
if not self.hosts and not self.hostfile:
|
||||
self.allhosts = True
|
||||
else:
|
||||
self.allhosts = False
|
||||
if not self.tags and not self.tagfile:
|
||||
self.tagfile = "-"
|
||||
|
||||
if self.hostfile == "-" and self.tagfile == "-":
|
||||
raise cdist.Error("Cannot read both, hosts and tags, from stdin")
|
||||
|
||||
def _read_input_tags(self):
|
||||
self.input_tags = set()
|
||||
for tag in itertools.chain(self._input_values(self.tags),
|
||||
self._input_values(self.tagfile)):
|
||||
self.input_tags.add(tag)
|
||||
|
||||
def _action(self, host):
|
||||
host_tags = self._get_host_tags(host)
|
||||
if host_tags is None:
|
||||
print("Host \'{}\' does not exist, skipping".format(host),
|
||||
file=sys.stderr)
|
||||
return
|
||||
self.log.debug("existing host_tags: {}".format(host_tags))
|
||||
if self.action == "del" and self.all:
|
||||
host_tags = set()
|
||||
else:
|
||||
for tag in self.input_tags:
|
||||
if self.action == "add":
|
||||
self.log.info("Adding tag \'{}\' for host \'{}\'".format(
|
||||
tag, host))
|
||||
host_tags.add(tag)
|
||||
elif self.action == "del":
|
||||
self.log.info("Deleting tag \'{}\' for host \'{}\'".format(
|
||||
tag, host))
|
||||
if tag in host_tags:
|
||||
host_tags.remove(tag)
|
||||
self.log.debug("new host tags: {}".format(host_tags))
|
||||
if not self._write_host_tags(host, host_tags):
|
||||
self.log.info("{} does not exist, skipped".format(host))
|
||||
|
||||
def run(self):
|
||||
if self.allhosts:
|
||||
self.log.debug("Doing for all hosts")
|
||||
it = self._all_hosts()
|
||||
else:
|
||||
self.log.debug("Doing for specified hosts")
|
||||
it = itertools.chain(self._input_values(self.hosts),
|
||||
self._input_values(self.hostfile))
|
||||
if not(self.action == "del" and self.all):
|
||||
self._read_input_tags()
|
||||
for host in it:
|
||||
self._action(host)
|
|
@ -44,6 +44,7 @@ class Shell(object):
|
|||
"cdist-shell-no-target-host",
|
||||
"cdist-shell-no-target-host",
|
||||
)
|
||||
self.target_host_tags = ""
|
||||
|
||||
host_dir_name = cdist.str_hash(self.target_host[0])
|
||||
base_root_path = tempfile.mkdtemp()
|
||||
|
@ -51,6 +52,7 @@ class Shell(object):
|
|||
|
||||
self.local = cdist.exec.local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=host_base_path,
|
||||
host_dir_name=host_dir_name)
|
||||
|
||||
|
@ -77,6 +79,7 @@ class Shell(object):
|
|||
'__manifest': self.local.manifest_path,
|
||||
'__explorer': self.local.global_explorer_path,
|
||||
'__files': self.local.files_path,
|
||||
'__target_host_tags': self.local.target_host_tags,
|
||||
}
|
||||
|
||||
self.env.update(additional_env)
|
||||
|
|
|
@ -42,6 +42,7 @@ class CdistTestCase(unittest.TestCase):
|
|||
'cdisttesthost',
|
||||
'cdisttesthost',
|
||||
)
|
||||
target_host_tags = "tag1,tag2,tag3"
|
||||
|
||||
def mkdtemp(self, **kwargs):
|
||||
return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs)
|
||||
|
|
|
@ -46,6 +46,7 @@ class CodeTestCase(test.CdistTestCase):
|
|||
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=self.host_base_path,
|
||||
host_dir_name=self.hostdir,
|
||||
exec_path=cdist.test.cdist_exec_path,
|
||||
|
@ -97,6 +98,8 @@ class CodeTestCase(test.CdistTestCase):
|
|||
self.cdist_object.object_id)
|
||||
self.assertEqual(output_dict['__object_name'], self.cdist_object.name)
|
||||
self.assertEqual(output_dict['__files'], self.local.files_path)
|
||||
self.assertEqual(output_dict['__target_host_tags'],
|
||||
self.local.target_host_tags)
|
||||
|
||||
def test_run_gencode_remote_environment(self):
|
||||
output_string = self.code.run_gencode_remote(self.cdist_object)
|
||||
|
@ -120,6 +123,8 @@ class CodeTestCase(test.CdistTestCase):
|
|||
self.cdist_object.object_id)
|
||||
self.assertEqual(output_dict['__object_name'], self.cdist_object.name)
|
||||
self.assertEqual(output_dict['__files'], self.local.files_path)
|
||||
self.assertEqual(output_dict['__target_host_tags'],
|
||||
self.local.target_host_tags)
|
||||
|
||||
def test_transfer_code_remote(self):
|
||||
self.cdist_object.code_remote = self.code.run_gencode_remote(
|
||||
|
|
|
@ -9,3 +9,4 @@ echo "echo __object: $__object"
|
|||
echo "echo __object_id: $__object_id"
|
||||
echo "echo __object_name: $__object_name"
|
||||
echo "echo __files: $__files"
|
||||
echo "echo __target_host_tags: $__target_host_tags"
|
||||
|
|
|
@ -60,6 +60,7 @@ class ConfigRunTestCase(test.CdistTestCase):
|
|||
os.makedirs(self.host_base_path)
|
||||
self.local = cdist.exec.local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=self.host_base_path,
|
||||
host_dir_name=self.hostdir)
|
||||
|
||||
|
@ -164,6 +165,7 @@ class ConfigRunTestCase(test.CdistTestCase):
|
|||
"""Test if the dryrun option is working like expected"""
|
||||
drylocal = cdist.exec.local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=self.host_base_path,
|
||||
host_dir_name=self.hostdir,
|
||||
# exec_path can not derivated from sys.argv in case of unittest
|
||||
|
@ -181,6 +183,7 @@ class ConfigRunTestCase(test.CdistTestCase):
|
|||
"""Test to show dependency resolver warning message."""
|
||||
local = cdist.exec.local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=self.host_base_path,
|
||||
host_dir_name=self.hostdir,
|
||||
exec_path=os.path.abspath(os.path.join(
|
||||
|
|
|
@ -53,6 +53,7 @@ class EmulatorTestCase(test.CdistTestCase):
|
|||
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=host_base_path,
|
||||
host_dir_name=hostdir,
|
||||
exec_path=test.cdist_exec_path,
|
||||
|
@ -156,6 +157,7 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase):
|
|||
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=host_base_path,
|
||||
host_dir_name=hostdir,
|
||||
exec_path=test.cdist_exec_path,
|
||||
|
@ -246,6 +248,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase):
|
|||
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=host_base_path,
|
||||
host_dir_name=hostdir,
|
||||
exec_path=test.cdist_exec_path,
|
||||
|
@ -279,6 +282,7 @@ class OverrideTestCase(test.CdistTestCase):
|
|||
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=host_base_path,
|
||||
host_dir_name=hostdir,
|
||||
exec_path=test.cdist_exec_path,
|
||||
|
@ -322,6 +326,7 @@ class ArgumentsTestCase(test.CdistTestCase):
|
|||
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=host_base_path,
|
||||
host_dir_name=hostdir,
|
||||
exec_path=test.cdist_exec_path,
|
||||
|
@ -445,6 +450,7 @@ class StdinTestCase(test.CdistTestCase):
|
|||
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=host_base_path,
|
||||
host_dir_name=hostdir,
|
||||
exec_path=test.cdist_exec_path,
|
||||
|
@ -511,6 +517,7 @@ class EmulatorAlreadyExistingRequirementsWarnTestCase(test.CdistTestCase):
|
|||
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=host_base_path,
|
||||
host_dir_name=hostdir,
|
||||
exec_path=test.cdist_exec_path,
|
||||
|
|
|
@ -50,6 +50,7 @@ class ExplorerClassTestCase(test.CdistTestCase):
|
|||
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=base_root_path,
|
||||
host_dir_name=hostdir,
|
||||
exec_path=test.cdist_exec_path,
|
||||
|
|
476
cdist/test/inventory/__init__.py
Normal file
476
cdist/test/inventory/__init__.py
Normal file
|
@ -0,0 +1,476 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import cdist
|
||||
import os.path as op
|
||||
import unittest
|
||||
import sys
|
||||
from cdist import test
|
||||
from cdist import inventory
|
||||
from io import StringIO
|
||||
|
||||
my_dir = op.abspath(op.dirname(__file__))
|
||||
fixtures = op.join(my_dir, 'fixtures')
|
||||
inventory_dir = op.join(fixtures, "inventory")
|
||||
|
||||
|
||||
class InventoryTestCase(test.CdistTestCase):
|
||||
|
||||
def _create_host_with_tags(self, host, tags):
|
||||
os.makedirs(inventory_dir, exist_ok=True)
|
||||
hostfile = op.join(inventory_dir, host)
|
||||
with open(hostfile, "w") as f:
|
||||
for x in tags:
|
||||
f.write("{}\n".format(x))
|
||||
|
||||
def setUp(self):
|
||||
self.maxDiff = None
|
||||
self.db = {
|
||||
"loadbalancer1": ["loadbalancer", "all", "europe", ],
|
||||
"loadbalancer2": ["loadbalancer", "all", "europe", ],
|
||||
"loadbalancer3": ["loadbalancer", "all", "africa", ],
|
||||
"loadbalancer4": ["loadbalancer", "all", "africa", ],
|
||||
"web1": ["web", "all", "static", ],
|
||||
"web2": ["web", "all", "dynamic", ],
|
||||
"web3": ["web", "all", "dynamic", ],
|
||||
"shell1": ["shell", "all", "free", ],
|
||||
"shell2": ["shell", "all", "free", ],
|
||||
"shell3": ["shell", "all", "charge", ],
|
||||
"shell4": ["shell", "all", "charge", ],
|
||||
"monty": ["web", "python", "shell", ],
|
||||
"python": ["web", "python", "shell", ],
|
||||
}
|
||||
for x in self.db:
|
||||
self.db[x] = sorted(self.db[x])
|
||||
for host in self.db:
|
||||
self._create_host_with_tags(host, self.db[host])
|
||||
self.sys_stdout = sys.stdout
|
||||
out = StringIO()
|
||||
sys.stdout = out
|
||||
|
||||
def _get_output(self):
|
||||
sys.stdout.flush()
|
||||
output = sys.stdout.getvalue().strip()
|
||||
return output
|
||||
|
||||
def tearDown(self):
|
||||
sys.stdout = self.sys_stdout
|
||||
shutil.rmtree(inventory_dir)
|
||||
|
||||
def test_inventory_create_db(self):
|
||||
dbdir = op.join(fixtures, "foo")
|
||||
inv = inventory.Inventory(db_basedir=dbdir)
|
||||
self.assertTrue(os.path.isdir(dbdir))
|
||||
self.assertEqual(inv.db_basedir, dbdir)
|
||||
shutil.rmtree(inv.db_basedir)
|
||||
|
||||
# InventoryList
|
||||
def test_inventory_list_print(self):
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir)
|
||||
invList.run()
|
||||
output = self._get_output()
|
||||
self.assertTrue(' ' in output)
|
||||
|
||||
def test_inventory_list_print_host_only(self):
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
list_only_host=True)
|
||||
invList.run()
|
||||
output = self._get_output()
|
||||
self.assertFalse(' ' in output)
|
||||
|
||||
def test_inventory_list_all(self):
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir)
|
||||
entries = invList.entries()
|
||||
db = {host: sorted(tags) for host, tags in entries}
|
||||
self.assertEqual(db, self.db)
|
||||
|
||||
def test_inventory_list_by_host_hosts(self):
|
||||
hosts = ("web1", "web2", "web3",)
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hosts=hosts)
|
||||
entries = invList.entries()
|
||||
db = {host: sorted(tags) for host, tags in entries}
|
||||
expected_db = {host: sorted(self.db[host]) for host in hosts}
|
||||
self.assertEqual(db, expected_db)
|
||||
|
||||
def test_inventory_list_by_host_hostfile(self):
|
||||
hosts = ("web1", "web2", "web3",)
|
||||
hostfile = op.join(fixtures, "hosts")
|
||||
with open(hostfile, "w") as f:
|
||||
for x in hosts:
|
||||
f.write("{}\n".format(x))
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hostfile=hostfile)
|
||||
entries = invList.entries()
|
||||
db = {host: sorted(tags) for host, tags in entries}
|
||||
expected_db = {host: sorted(self.db[host]) for host in hosts}
|
||||
self.assertEqual(db, expected_db)
|
||||
os.remove(hostfile)
|
||||
|
||||
def test_inventory_list_by_host_hosts_hostfile(self):
|
||||
hosts = ("shell1", "shell4",)
|
||||
hostsf = ("web1", "web2", "web3",)
|
||||
hostfile = op.join(fixtures, "hosts")
|
||||
with open(hostfile, "w") as f:
|
||||
for x in hostsf:
|
||||
f.write("{}\n".format(x))
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hosts=hosts, hostfile=hostfile)
|
||||
entries = invList.entries()
|
||||
db = {host: sorted(tags) for host, tags in entries}
|
||||
import itertools
|
||||
expected_db = {host: sorted(self.db[host]) for host in
|
||||
itertools.chain(hostsf, hosts)}
|
||||
self.assertEqual(db, expected_db)
|
||||
os.remove(hostfile)
|
||||
|
||||
def _gen_expected_db_for_tags(self, tags):
|
||||
db = {}
|
||||
for host in self.db:
|
||||
for tag in tags:
|
||||
if tag in self.db[host]:
|
||||
db[host] = self.db[host]
|
||||
break
|
||||
return db
|
||||
|
||||
def _gen_expected_db_for_has_all_tags(self, tags):
|
||||
db = {}
|
||||
for host in self.db:
|
||||
if set(tags).issubset(set(self.db[host])):
|
||||
db[host] = self.db[host]
|
||||
return db
|
||||
|
||||
def test_inventory_list_by_tag_hosts(self):
|
||||
tags = ("web", "shell",)
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
istag=True, hosts=tags)
|
||||
entries = invList.entries()
|
||||
db = {host: sorted(tags) for host, tags in entries}
|
||||
expected_db = self._gen_expected_db_for_tags(tags)
|
||||
self.assertEqual(db, expected_db)
|
||||
|
||||
def test_inventory_list_by_tag_hostfile(self):
|
||||
tags = ("web", "shell",)
|
||||
tagfile = op.join(fixtures, "tags")
|
||||
with open(tagfile, "w") as f:
|
||||
for x in tags:
|
||||
f.write("{}\n".format(x))
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
istag=True, hostfile=tagfile)
|
||||
entries = invList.entries()
|
||||
db = {host: sorted(tags) for host, tags in entries}
|
||||
expected_db = self._gen_expected_db_for_tags(tags)
|
||||
self.assertEqual(db, expected_db)
|
||||
os.remove(tagfile)
|
||||
|
||||
def test_inventory_list_by_tag_hosts_hostfile(self):
|
||||
tags = ("web", "shell",)
|
||||
tagsf = ("dynamic", "europe",)
|
||||
tagfile = op.join(fixtures, "tags")
|
||||
with open(tagfile, "w") as f:
|
||||
for x in tagsf:
|
||||
f.write("{}\n".format(x))
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
istag=True, hosts=tags,
|
||||
hostfile=tagfile)
|
||||
entries = invList.entries()
|
||||
db = {host: sorted(tags) for host, tags in entries}
|
||||
import itertools
|
||||
expected_db = self._gen_expected_db_for_tags(tags + tagsf)
|
||||
self.assertEqual(db, expected_db)
|
||||
os.remove(tagfile)
|
||||
|
||||
def test_inventory_list_by_tag_has_all_tags(self):
|
||||
tags = ("web", "python", "shell",)
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
istag=True, hosts=tags,
|
||||
has_all_tags=True)
|
||||
entries = invList.entries()
|
||||
db = {host: sorted(tags) for host, tags in entries}
|
||||
expected_db = self._gen_expected_db_for_has_all_tags(tags)
|
||||
self.assertEqual(db, expected_db)
|
||||
|
||||
# InventoryHost
|
||||
def test_inventory_host_add_hosts(self):
|
||||
hosts = ("spam", "eggs", "foo",)
|
||||
invHost = inventory.InventoryHost(db_basedir=inventory_dir,
|
||||
action="add", hosts=hosts)
|
||||
invHost.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir)
|
||||
expected_hosts = tuple(x for x in invList.host_entries() if x in hosts)
|
||||
self.assertEqual(sorted(hosts), sorted(expected_hosts))
|
||||
|
||||
def test_inventory_host_add_hostfile(self):
|
||||
hosts = ("spam-new", "eggs-new", "foo-new",)
|
||||
hostfile = op.join(fixtures, "hosts")
|
||||
with open(hostfile, "w") as f:
|
||||
for x in hosts:
|
||||
f.write("{}\n".format(x))
|
||||
invHost = inventory.InventoryHost(db_basedir=inventory_dir,
|
||||
action="add", hostfile=hostfile)
|
||||
invHost.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir)
|
||||
expected_hosts = tuple(x for x in invList.host_entries() if x in hosts)
|
||||
self.assertEqual(sorted(hosts), sorted(expected_hosts))
|
||||
os.remove(hostfile)
|
||||
|
||||
def test_inventory_host_add_hosts_hostfile(self):
|
||||
hosts = ("spam-spam", "eggs-spam", "foo-spam",)
|
||||
hostf = ("spam-eggs-spam", "spam-foo-spam",)
|
||||
hostfile = op.join(fixtures, "hosts")
|
||||
with open(hostfile, "w") as f:
|
||||
for x in hostf:
|
||||
f.write("{}\n".format(x))
|
||||
invHost = inventory.InventoryHost(db_basedir=inventory_dir,
|
||||
action="add", hosts=hosts,
|
||||
hostfile=hostfile)
|
||||
invHost.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hosts=hosts + hostf)
|
||||
expected_hosts = tuple(invList.host_entries())
|
||||
self.assertEqual(sorted(hosts + hostf), sorted(expected_hosts))
|
||||
os.remove(hostfile)
|
||||
|
||||
def test_inventory_host_del_hosts(self):
|
||||
hosts = ("web1", "shell1",)
|
||||
invHost = inventory.InventoryHost(db_basedir=inventory_dir,
|
||||
action="del", hosts=hosts)
|
||||
invHost.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hosts=hosts)
|
||||
expected_hosts = tuple(invList.host_entries())
|
||||
self.assertTupleEqual(expected_hosts, ())
|
||||
|
||||
def test_inventory_host_del_hostfile(self):
|
||||
hosts = ("loadbalancer3", "loadbalancer4",)
|
||||
hostfile = op.join(fixtures, "hosts")
|
||||
with open(hostfile, "w") as f:
|
||||
for x in hosts:
|
||||
f.write("{}\n".format(x))
|
||||
invHost = inventory.InventoryHost(db_basedir=inventory_dir,
|
||||
action="del", hostfile=hostfile)
|
||||
invHost.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hosts=hosts)
|
||||
expected_hosts = tuple(invList.host_entries())
|
||||
self.assertTupleEqual(expected_hosts, ())
|
||||
os.remove(hostfile)
|
||||
|
||||
def test_inventory_host_del_hosts_hostfile(self):
|
||||
hosts = ("loadbalancer1", "loadbalancer2",)
|
||||
hostf = ("web2", "shell2",)
|
||||
hostfile = op.join(fixtures, "hosts")
|
||||
with open(hostfile, "w") as f:
|
||||
for x in hostf:
|
||||
f.write("{}\n".format(x))
|
||||
invHost = inventory.InventoryHost(db_basedir=inventory_dir,
|
||||
action="del", hosts=hosts,
|
||||
hostfile=hostfile)
|
||||
invHost.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hosts=hosts + hostf)
|
||||
expected_hosts = tuple(invList.host_entries())
|
||||
self.assertTupleEqual(expected_hosts, ())
|
||||
os.remove(hostfile)
|
||||
|
||||
@unittest.expectedFailure
|
||||
def test_inventory_host_invalid_host(self):
|
||||
try:
|
||||
invalid_hostfile = op.join(inventory_dir, "invalid")
|
||||
os.mkdir(invalid_hostfile)
|
||||
hosts = ("invalid",)
|
||||
invHost = inventory.InventoryHost(db_basedir=inventory_dir,
|
||||
action="del", hosts=hosts)
|
||||
invHost.run()
|
||||
except e:
|
||||
os.rmdir(invalid_hostfile)
|
||||
raise e
|
||||
|
||||
# InventoryTag
|
||||
def test_inventory_tag_init(self):
|
||||
invTag = inventory.InventoryTag(db_basedir=inventory_dir,
|
||||
action="add")
|
||||
self.assertTrue(invTag.allhosts)
|
||||
self.assertEqual(invTag.tagfile, "-")
|
||||
|
||||
def test_inventory_tag_stdin_multiple_hosts(self):
|
||||
try:
|
||||
invTag = inventory.InventoryTag(db_basedir=inventory_dir,
|
||||
action="add", tagfile="-",
|
||||
hosts=("host1", "host2",))
|
||||
except e:
|
||||
self.fail()
|
||||
|
||||
def test_inventory_tag_stdin_hostfile(self):
|
||||
try:
|
||||
invTag = inventory.InventoryTag(db_basedir=inventory_dir,
|
||||
action="add", tagfile="-",
|
||||
hostfile="hosts")
|
||||
except e:
|
||||
self.fail()
|
||||
|
||||
@unittest.expectedFailure
|
||||
def test_inventory_tag_stdin_both(self):
|
||||
invTag = inventory.InventoryTag(db_basedir=inventory_dir,
|
||||
action="add", tagfile="-",
|
||||
hostfile="-")
|
||||
|
||||
def test_inventory_tag_add_for_all_hosts(self):
|
||||
tags = ("spam-spam-spam", "spam-spam-eggs",)
|
||||
tagsf = ("spam-spam-spam-eggs", "spam-spam-eggs-spam",)
|
||||
tagfile = op.join(fixtures, "tags")
|
||||
with open(tagfile, "w") as f:
|
||||
for x in tagsf:
|
||||
f.write("{}\n".format(x))
|
||||
invTag = inventory.InventoryTag(db_basedir=inventory_dir,
|
||||
action="add", tags=tags,
|
||||
tagfile=tagfile)
|
||||
invTag.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir)
|
||||
failed = False
|
||||
for host, taglist in invList.entries():
|
||||
for x in tagsf + tags:
|
||||
if x not in taglist:
|
||||
failed = True
|
||||
break
|
||||
if failed:
|
||||
break
|
||||
os.remove(tagfile)
|
||||
if failed:
|
||||
self.fail()
|
||||
|
||||
def test_inventory_tag_add(self):
|
||||
tags = ("spam-spam-spam", "spam-spam-eggs",)
|
||||
tagsf = ("spam-spam-spam-eggs", "spam-spam-eggs-spam",)
|
||||
hosts = ("loadbalancer1", "loadbalancer2", "shell2",)
|
||||
hostsf = ("web2", "web3",)
|
||||
tagfile = op.join(fixtures, "tags")
|
||||
with open(tagfile, "w") as f:
|
||||
for x in tagsf:
|
||||
f.write("{}\n".format(x))
|
||||
hostfile = op.join(fixtures, "hosts")
|
||||
with open(hostfile, "w") as f:
|
||||
for x in hostsf:
|
||||
f.write("{}\n".format(x))
|
||||
invTag = inventory.InventoryTag(db_basedir=inventory_dir,
|
||||
action="add", tags=tags,
|
||||
tagfile=tagfile, hosts=hosts,
|
||||
hostfile=hostfile)
|
||||
invTag.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hosts=hosts + hostsf)
|
||||
failed = False
|
||||
for host, taglist in invList.entries():
|
||||
if host not in hosts + hostsf:
|
||||
failed = True
|
||||
break
|
||||
for x in tagsf + tags:
|
||||
if x not in taglist:
|
||||
failed = True
|
||||
break
|
||||
if failed:
|
||||
break
|
||||
os.remove(tagfile)
|
||||
os.remove(hostfile)
|
||||
if failed:
|
||||
self.fail()
|
||||
|
||||
def test_inventory_tag_del_for_all_hosts(self):
|
||||
tags = ("all",)
|
||||
tagsf = ("charge",)
|
||||
tagfile = op.join(fixtures, "tags")
|
||||
with open(tagfile, "w") as f:
|
||||
for x in tagsf:
|
||||
f.write("{}\n".format(x))
|
||||
invTag = inventory.InventoryTag(db_basedir=inventory_dir,
|
||||
action="del", tags=tags,
|
||||
tagfile=tagfile)
|
||||
invTag.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir)
|
||||
failed = False
|
||||
for host, taglist in invList.entries():
|
||||
for x in tagsf + tags:
|
||||
if x in taglist:
|
||||
failed = True
|
||||
break
|
||||
if failed:
|
||||
break
|
||||
os.remove(tagfile)
|
||||
if failed:
|
||||
self.fail()
|
||||
|
||||
def test_inventory_tag_del(self):
|
||||
tags = ("europe", "africa",)
|
||||
tagsf = ("free", )
|
||||
hosts = ("loadbalancer1", "loadbalancer2", "shell2",)
|
||||
hostsf = ("web2", "web3",)
|
||||
tagfile = op.join(fixtures, "tags")
|
||||
with open(tagfile, "w") as f:
|
||||
for x in tagsf:
|
||||
f.write("{}\n".format(x))
|
||||
hostfile = op.join(fixtures, "hosts")
|
||||
with open(hostfile, "w") as f:
|
||||
for x in hostsf:
|
||||
f.write("{}\n".format(x))
|
||||
invTag = inventory.InventoryTag(db_basedir=inventory_dir,
|
||||
action="del", tags=tags,
|
||||
tagfile=tagfile, hosts=hosts,
|
||||
hostfile=hostfile)
|
||||
invTag.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hosts=hosts + hostsf)
|
||||
failed = False
|
||||
for host, taglist in invList.entries():
|
||||
if host not in hosts + hostsf:
|
||||
failed = True
|
||||
break
|
||||
for x in tagsf + tags:
|
||||
if x in taglist:
|
||||
failed = True
|
||||
break
|
||||
if failed:
|
||||
break
|
||||
os.remove(tagfile)
|
||||
os.remove(hostfile)
|
||||
if failed:
|
||||
self.fail()
|
||||
|
||||
def test_inventory_tag_del_all_tags(self):
|
||||
hosts = ("web3", "shell1",)
|
||||
hostsf = ("shell2", "loadbalancer1",)
|
||||
hostfile = op.join(fixtures, "hosts")
|
||||
with open(hostfile, "w") as f:
|
||||
for x in hostsf:
|
||||
f.write("{}\n".format(x))
|
||||
invHost = inventory.InventoryHost(db_basedir=inventory_dir,
|
||||
action="del", all=True,
|
||||
hosts=hosts, hostfile=hostfile)
|
||||
invHost.run()
|
||||
invList = inventory.InventoryList(db_basedir=inventory_dir,
|
||||
hosts=hosts + hostsf)
|
||||
for host, htags in invList.entries():
|
||||
self.assertEqual(htags, ())
|
||||
os.remove(hostfile)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
|
@ -53,6 +53,7 @@ class ManifestTestCase(test.CdistTestCase):
|
|||
base_root_path = os.path.join(out_path, hostdir)
|
||||
self.local = local.Local(
|
||||
target_host=self.target_host,
|
||||
target_host_tags=self.target_host_tags,
|
||||
base_root_path=base_root_path,
|
||||
host_dir_name=hostdir,
|
||||
exec_path=cdist.test.cdist_exec_path,
|
||||
|
@ -93,6 +94,8 @@ class ManifestTestCase(test.CdistTestCase):
|
|||
self.local.type_path)
|
||||
self.assertEqual(output_dict['__manifest'], self.local.manifest_path)
|
||||
self.assertEqual(output_dict['__files'], self.local.files_path)
|
||||
self.assertEqual(output_dict['__target_host_tags'],
|
||||
self.local.target_host_tags)
|
||||
|
||||
def test_type_manifest_environment(self):
|
||||
cdist_type = core.CdistType(self.local.type_path, '__dump_environment')
|
||||
|
@ -126,6 +129,8 @@ class ManifestTestCase(test.CdistTestCase):
|
|||
self.assertEqual(output_dict['__object_id'], cdist_object.object_id)
|
||||
self.assertEqual(output_dict['__object_name'], cdist_object.name)
|
||||
self.assertEqual(output_dict['__files'], self.local.files_path)
|
||||
self.assertEqual(output_dict['__target_host_tags'],
|
||||
self.local.target_host_tags)
|
||||
|
||||
def test_debug_env_setup(self):
|
||||
current_level = self.log.getEffectiveLevel()
|
||||
|
|
|
@ -9,4 +9,5 @@ __global: $__global
|
|||
__cdist_type_base_path: $__cdist_type_base_path
|
||||
__manifest: $__manifest
|
||||
__files: $__files
|
||||
__target_host_tags: $__target_host_tags
|
||||
DONE
|
||||
|
|
|
@ -13,4 +13,5 @@ __object: $__object
|
|||
__object_id: $__object_id
|
||||
__object_name: $__object_name
|
||||
__files: $__files
|
||||
__target_host_tags: $__target_host_tags
|
||||
DONE
|
||||
|
|
|
@ -5,8 +5,8 @@ _cdist()
|
|||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
prevprev="${COMP_WORDS[COMP_CWORD-2]}"
|
||||
opts="-h --help -d --debug -v --verbose -V --version"
|
||||
cmds="banner shell config install"
|
||||
opts="-h --help -q --quiet -v --verbose -V --version"
|
||||
cmds="banner config install inventory shell"
|
||||
|
||||
case "${prevprev}" in
|
||||
shell)
|
||||
|
@ -18,6 +18,41 @@ _cdist()
|
|||
;;
|
||||
esac
|
||||
;;
|
||||
inventory)
|
||||
case "${prev}" in
|
||||
list)
|
||||
opts="-h --help -q --quiet -v --verbose -b --beta \
|
||||
-I --invento/y -a --all -f --file -H --host-only \
|
||||
-t --tag"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
add-host)
|
||||
opts="-h --help -q --quiet -v --verbose -b --beta \
|
||||
-I --inventory -f --file"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
del-host)
|
||||
opts="-h --help -q --quiet -v --verbose -b --beta \
|
||||
-I --inventory -a --all -f --file"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
add-tag)
|
||||
opts="-h --help -q --quiet -v --verbose -b --beta \
|
||||
-I --inventory -f --file -T --tag-file -t --taglist"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
del-tag)
|
||||
opts="-h --help -q --quiet -v --verbose -b --beta \
|
||||
-I --inventory -a --all -f --file -T --tag-file -t --taglist"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${prev}" in
|
||||
|
@ -26,23 +61,31 @@ _cdist()
|
|||
return 0
|
||||
;;
|
||||
banner)
|
||||
opts="-h --help -d --debug -v --verbose"
|
||||
opts="-h --help -q --quiet -v --verbose"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
shell)
|
||||
opts="-h --help -d --debug -v --verbose -s --shell"
|
||||
opts="-h --help -q --quiet -v --verbose -s --shell"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
config|install)
|
||||
opts="-h --help -d --debug -v --verbose -b --beta \
|
||||
-C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs \
|
||||
-n --dry-run -o --out-dir -p --parallel -r --remote-out-dir -s --sequential \
|
||||
--remote-copy --remote-exec"
|
||||
opts="-h --help -q --quiet -v --verbose -b --beta \
|
||||
-I --inventory -C --cache-path-pattern -c --conf-dir \
|
||||
-f --file -i --initial-manifest -A --all-tagged \
|
||||
-j --jobs -n --dry-run -o --out-dir -p --parallel \
|
||||
-r --remote-out-dir \
|
||||
-s --sequential --remote-copy --remote-exec -t --tag -a --all"
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
inventory)
|
||||
cmds="list add-host del-host add-tag del-tag"
|
||||
opts="-h --help -q --quiet -v --verbose"
|
||||
COMPREPLY=( $(compgen -W "${opts} ${cmds}" -- ${cur}) )
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -11,16 +11,16 @@ _cdist()
|
|||
|
||||
case $state in
|
||||
opts_cmds)
|
||||
_arguments '1:Options and commands:(banner config shell install -h --help -d --debug -v --verbose -V --version)'
|
||||
_arguments '1:Options and commands:(banner config install inventory shell -h --help -q --quiet -v --verbose -V --version)'
|
||||
;;
|
||||
*)
|
||||
case $words[2] in
|
||||
-*)
|
||||
opts=(-h --help -d --debug -v --verbose -V --version)
|
||||
opts=(-h --help -q --quiet -v --verbose -V --version)
|
||||
compadd "$@" -- $opts
|
||||
;;
|
||||
banner)
|
||||
opts=(-h --help -d --debug -v --verbose)
|
||||
opts=(-h --help -q --quiet -v --verbose)
|
||||
compadd "$@" -- $opts
|
||||
;;
|
||||
shell)
|
||||
|
@ -30,16 +30,45 @@ _cdist()
|
|||
compadd "$@" -- $shells
|
||||
;;
|
||||
*)
|
||||
opts=(-h --help -d --debug -v --verbose -s --shell)
|
||||
opts=(-h --help -q --quiet -v --verbose -s --shell)
|
||||
compadd "$@" -- $opts
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
config|install)
|
||||
opts=(-h --help -d --debug -v --verbose -b --beta -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -r --remote-out-dir -s --sequential --remote-copy --remote-exec)
|
||||
opts=(-h --help -q --quiet -v --verbose -a --all -b --beta -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -r --remote-out-dir -s --sequential --remote-copy --remote-exec -t --tag -I --inventory -A --all-tagged)
|
||||
compadd "$@" -- $opts
|
||||
;;
|
||||
*)
|
||||
inventory)
|
||||
case $words[3] in
|
||||
list)
|
||||
opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -a --all -f --file -H --host-only -t --tag)
|
||||
compadd "$@" -- $opts
|
||||
;;
|
||||
add-host)
|
||||
opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -f --file)
|
||||
compadd "$@" -- $opts
|
||||
;;
|
||||
del-host)
|
||||
opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -a --all -f --file)
|
||||
compadd "$@" -- $opts
|
||||
;;
|
||||
add-tag)
|
||||
opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -f --file -T --tag-file -t --taglist)
|
||||
compadd "$@" -- $opts
|
||||
;;
|
||||
del-tag)
|
||||
opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -a --all -f --file -T --tag-file -t --taglist)
|
||||
compadd "$@" -- $opts
|
||||
;;
|
||||
*)
|
||||
cmds=(list add-host del-host add-tag del-tag)
|
||||
opts=(-h --help -q --quiet -v --verbose)
|
||||
compadd "$@" -- $cmds $opts
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
esac
|
||||
|
|
|
@ -2,6 +2,11 @@ Changelog
|
|||
---------
|
||||
|
||||
next:
|
||||
* Core: Add inventory functionality (Darko Poljak)
|
||||
* Core: Expose inventory host tags in __target_host_tags env var (Darko Poljak)
|
||||
* Type __timezone: Check current timezone before doing anything (Ander Punnar)
|
||||
|
||||
4.5.0: 2017-07-20
|
||||
* Types: Fix install types (Steven Armstrong)
|
||||
* Core: Add -r command line option for setting remote base path (Steven Armstrong)
|
||||
* Core: Allow manifest and gencode scripts to be written in any language (Darko Poljak)
|
||||
|
|
|
@ -97,7 +97,7 @@ Including a possible common base that is reused across the different sites::
|
|||
git merge common
|
||||
|
||||
|
||||
The following **.git/config** is taken from a real world scenario:
|
||||
The following **.git/config** is taken from a real world scenario::
|
||||
|
||||
# Track upstream, merge from time to time
|
||||
[remote "upstream"]
|
||||
|
|
211
docs/src/cdist-inventory.rst
Normal file
211
docs/src/cdist-inventory.rst
Normal file
|
@ -0,0 +1,211 @@
|
|||
Inventory
|
||||
=========
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
cdist comes with simple built-in tag based inventory. It is a simple inventory
|
||||
with list of hosts and a host has a list of tags.
|
||||
Inventory functionality is still in **beta** so it can be used only if beta
|
||||
command line flag is specified (-b, --beta) or setting CDIST_BETA env var.
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The idea is to have simple tagging inventory. There is a list of hosts and for
|
||||
each host there are tags. Inventory database is a set of files under inventory
|
||||
database base directory. Filename equals hostname. Each file contains tags for
|
||||
hostname with each tag on its own line.
|
||||
|
||||
Using inventory you can now configure hosts by selecting them by tags.
|
||||
|
||||
Tags have no values, as tags are just tags. Tag name-value would in this
|
||||
context mean that host has two tags and it is selected by specifying that both
|
||||
tags are present.
|
||||
|
||||
This inventory is **KISS** cdist built-in inventory database. You can maintain it
|
||||
using cdist inventory interface or using standard UNIX tools.
|
||||
|
||||
cdist inventory interface
|
||||
-------------------------
|
||||
|
||||
With cdist inventory interface you can list host(s) and tag(s), add host(s),
|
||||
add tag(s), delete host(s) and delete tag(s).
|
||||
|
||||
Configuring hosts using inventory
|
||||
---------------------------------
|
||||
|
||||
config command now has new options, **-t**, **-a** and **-A**.
|
||||
|
||||
**-A** means that all hosts in tag db is selected.
|
||||
|
||||
**-a** means that selected hosts must contain ALL specified tags.
|
||||
|
||||
**-t** means that host specifies tag - all hosts that have specified tags are
|
||||
selected.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# List inventory content
|
||||
$ cdist inventory list -b
|
||||
|
||||
# List inventory for specified host localhost
|
||||
$ cdist inventory list -b localhost
|
||||
|
||||
# List inventory for specified tag loadbalancer
|
||||
$ cdist inventory list -b -t loadbalancer
|
||||
|
||||
# Add hosts to inventory
|
||||
$ cdist inventory add-host -b web1 web2 web3
|
||||
|
||||
# Delete hosts from file old-hosts from inventory
|
||||
$ cdist inventory del-host -b -f old-hosts
|
||||
|
||||
# Add tags to specifed hosts
|
||||
$ cdist inventory add-tag -b -t europe,croatia,web,static web1 web2
|
||||
|
||||
# Add tag to all hosts in inventory
|
||||
$ cdist inventory add-tag -b -t vm
|
||||
|
||||
# Delete all tags from specified host
|
||||
$ cdist inventory del-tag -b -a localhost
|
||||
|
||||
# Delete tags read from stdin from hosts specified by file hosts
|
||||
$ cdist inventory del-tag -b -T - -f hosts
|
||||
|
||||
# Configure hosts from inventory with any of specified tags
|
||||
$ cdist config -b -t web dynamic
|
||||
|
||||
# Configure hosts from inventory with all specified tags
|
||||
$ cdist config -b -t -a web dynamic
|
||||
|
||||
# Configure all hosts from inventory db
|
||||
$ cdist config -b -A
|
||||
|
||||
Example of manipulating database
|
||||
--------------------------------
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ python3 scripts/cdist inventory list -b
|
||||
$ python3 scripts/cdist inventory add-host -b localhost
|
||||
$ python3 scripts/cdist inventory add-host -b test.mycloud.net
|
||||
$ python3 scripts/cdist inventory list -b
|
||||
localhost
|
||||
test.mycloud.net
|
||||
$ python3 scripts/cdist inventory add-host -b web1.mycloud.net web2.mycloud.net shell1.mycloud.net shell2.mycloud.net
|
||||
$ python3 scripts/cdist inventory list -b
|
||||
localhost
|
||||
test.mycloud.net
|
||||
web1.mycloud.net
|
||||
web2.mycloud.net
|
||||
shell1.mycloud.net
|
||||
shell2.mycloud.net
|
||||
$ python3 scripts/cdist inventory add-tag -b -t web web1.mycloud.net web2.mycloud.net
|
||||
$ python3 scripts/cdist inventory add-tag -b -t shell shell1.mycloud.net shell2.mycloud.net
|
||||
$ python3 scripts/cdist inventory add-tag -b -t cloud
|
||||
$ python3 scripts/cdist inventory list -b
|
||||
localhost cloud
|
||||
test.mycloud.net cloud
|
||||
web1.mycloud.net cloud,web
|
||||
web2.mycloud.net cloud,web
|
||||
shell1.mycloud.net cloud,shell
|
||||
shell2.mycloud.net cloud,shell
|
||||
$ python3 scripts/cdist inventory add-tag -b -t test,web,shell test.mycloud.net
|
||||
$ python3 scripts/cdist inventory list -b
|
||||
localhost cloud
|
||||
test.mycloud.net cloud,shell,test,web
|
||||
web1.mycloud.net cloud,web
|
||||
web2.mycloud.net cloud,web
|
||||
shell1.mycloud.net cloud,shell
|
||||
shell2.mycloud.net cloud,shell
|
||||
$ python3 scripts/cdist inventory del-tag -b -t shell test.mycloud.net
|
||||
$ python3 scripts/cdist inventory list -b
|
||||
localhost cloud
|
||||
test.mycloud.net cloud,test,web
|
||||
web1.mycloud.net cloud,web
|
||||
web2.mycloud.net cloud,web
|
||||
shell1.mycloud.net cloud,shell
|
||||
shell2.mycloud.net cloud,shell
|
||||
$ python3 scripts/cdist inventory add-tag -b -t all
|
||||
$ python3 scripts/cdist inventory add-tag -b -t mistake
|
||||
$ python3 scripts/cdist inventory list -b
|
||||
localhost all,cloud,mistake
|
||||
test.mycloud.net all,cloud,mistake,test,web
|
||||
web1.mycloud.net all,cloud,mistake,web
|
||||
web2.mycloud.net all,cloud,mistake,web
|
||||
shell1.mycloud.net all,cloud,mistake,shell
|
||||
shell2.mycloud.net all,cloud,mistake,shell
|
||||
$ python3 scripts/cdist inventory del-tag -b -t mistake
|
||||
$ python3 scripts/cdist inventory list -b
|
||||
localhost all,cloud
|
||||
test.mycloud.net all,cloud,test,web
|
||||
web1.mycloud.net all,cloud,web
|
||||
web2.mycloud.net all,cloud,web
|
||||
shell1.mycloud.net all,cloud,shell
|
||||
shell2.mycloud.net all,cloud,shell
|
||||
$ python3 scripts/cdist inventory del-host -b localhost
|
||||
$ python3 scripts/cdist inventory list -b
|
||||
test.mycloud.net all,cloud,test,web
|
||||
web1.mycloud.net all,cloud,web
|
||||
web2.mycloud.net all,cloud,web
|
||||
shell1.mycloud.net all,cloud,shell
|
||||
shell2.mycloud.net all,cloud,shell
|
||||
$ python3 scripts/cdist inventory list -b -t web
|
||||
test.mycloud.net all,cloud,test,web
|
||||
web1.mycloud.net all,cloud,web
|
||||
web2.mycloud.net all,cloud,web
|
||||
$ python3 scripts/cdist inventory list -b -t -a web test
|
||||
test.mycloud.net all,cloud,test,web
|
||||
$ python3 scripts/cdist inventory list -b -t -a web all
|
||||
test.mycloud.net all,cloud,test,web
|
||||
web1.mycloud.net all,cloud,web
|
||||
web2.mycloud.net all,cloud,web
|
||||
$ python3 scripts/cdist inventory list -b -t web all
|
||||
test.mycloud.net all,cloud,test,web
|
||||
web1.mycloud.net all,cloud,web
|
||||
web2.mycloud.net all,cloud,web
|
||||
shell1.mycloud.net all,cloud,shell
|
||||
shell2.mycloud.net all,cloud,shell
|
||||
$ cd cdist/inventory
|
||||
$ ls -1
|
||||
shell1.mycloud.net
|
||||
shell2.mycloud.net
|
||||
test.mycloud.net
|
||||
web1.mycloud.net
|
||||
web2.mycloud.net
|
||||
$ ls -l
|
||||
total 20
|
||||
-rw-r--r-- 1 darko darko 16 Jun 24 12:43 shell1.mycloud.net
|
||||
-rw-r--r-- 1 darko darko 16 Jun 24 12:43 shell2.mycloud.net
|
||||
-rw-r--r-- 1 darko darko 19 Jun 24 12:43 test.mycloud.net
|
||||
-rw-r--r-- 1 darko darko 14 Jun 24 12:43 web1.mycloud.net
|
||||
-rw-r--r-- 1 darko darko 14 Jun 24 12:43 web2.mycloud.net
|
||||
$ cat test.mycloud.net
|
||||
test
|
||||
all
|
||||
web
|
||||
cloud
|
||||
$ cat web2.mycloud.net
|
||||
all
|
||||
web
|
||||
cloud
|
||||
|
||||
For more info about inventory commands and options see `cdist <man1/cdist.html>`_\ (1).
|
||||
|
||||
Using external inventory
|
||||
------------------------
|
||||
|
||||
cdist can be used with any external inventory where external inventory is
|
||||
some storage or database from which you can get a list of hosts to configure.
|
||||
cdist can then be fed with this list of hosts through stdin or file using
|
||||
**-f** option. For example, if your host list is stored in sqlite3 database
|
||||
hosts.db and you want to select hosts which purpose is **django** then you
|
||||
can use it with cdist like:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ sqlite3 hosts.db "select hostname from hosts where purpose = 'django';" | cdist config
|
|
@ -63,6 +63,10 @@ cdist/conf/
|
|||
The distribution configuration directory.
|
||||
This contains types and explorers to be used.
|
||||
|
||||
cdist/inventory/
|
||||
The distribution inventory directory.
|
||||
This path is relative to cdist installation directory.
|
||||
|
||||
confdir
|
||||
Cdist will use all available configuration directories and create
|
||||
a temporary confdir containing links to the real configuration directories.
|
||||
|
@ -239,6 +243,9 @@ __target_fqdn
|
|||
This variable is derived from **__target_host**
|
||||
(using **socket.getfqdn()**).
|
||||
Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell.
|
||||
__target_host_tags
|
||||
Comma separated list of target host tags.
|
||||
Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell.
|
||||
__type
|
||||
Path to the current type.
|
||||
Available for: type manifest, type gencode.
|
||||
|
@ -274,6 +281,9 @@ CDIST_REMOTE_EXEC
|
|||
CDIST_REMOTE_COPY
|
||||
Use this command for remote copy (should behave like scp).
|
||||
|
||||
CDIST_INVENTORY_DIR
|
||||
Use this directory as inventory directory.
|
||||
|
||||
CDIST_BETA
|
||||
Enable beta functionalities.
|
||||
|
||||
|
|
|
@ -64,15 +64,23 @@ If a type is flagged with 'install' flag then it is used only with install comma
|
|||
With other commands, i.e. config, these types are skipped if used.
|
||||
|
||||
|
||||
Nonparallel types
|
||||
-----------------
|
||||
If a type is flagged with 'nonparallel' flag then its objects cannot be run in parallel
|
||||
when using -j option. Example of such a type is __package_dpkg type where dpkg itself
|
||||
prevents to be run in more than one instance.
|
||||
|
||||
|
||||
How to write a new type
|
||||
-----------------------
|
||||
A type consists of
|
||||
|
||||
- parameter (optional)
|
||||
- manifest (optional)
|
||||
- singleton (optional)
|
||||
- explorer (optional)
|
||||
- gencode (optional)
|
||||
- parameter (optional)
|
||||
- manifest (optional)
|
||||
- singleton (optional)
|
||||
- explorer (optional)
|
||||
- gencode (optional)
|
||||
- nonparallel (optional)
|
||||
|
||||
Types are stored below cdist/conf/type/. Their name should always be prefixed with
|
||||
two underscores (__) to prevent collisions with other executables in $PATH.
|
||||
|
@ -240,6 +248,19 @@ install: create the (empty) file "install" in your type directory:
|
|||
With other commands, i.e. config, it will be skipped if used.
|
||||
|
||||
|
||||
Nonparallel - only one instance can be run at a time
|
||||
----------------------------------------------------
|
||||
If objects of a type must not or cannot be run in parallel when using -j
|
||||
option, you must mark it as nonparallel: create the (empty) file "nonparallel"
|
||||
in your type directory:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
touch cdist/conf/type/__NAME/nonparallel
|
||||
|
||||
For example, package types are nonparallel types.
|
||||
|
||||
|
||||
The type explorers
|
||||
------------------
|
||||
If a type needs to explore specific details, it can provide type specific
|
||||
|
|
|
@ -24,6 +24,7 @@ Contents:
|
|||
cdist-explorer
|
||||
cdist-messaging
|
||||
cdist-parallelization
|
||||
cdist-inventory
|
||||
cdist-reference
|
||||
cdist-best-practice
|
||||
cdist-stages
|
||||
|
|
|
@ -11,23 +11,48 @@ SYNOPSIS
|
|||
|
||||
::
|
||||
|
||||
cdist [-h] [-v] [-V] {banner,config,shell,install} ...
|
||||
cdist [-h] [-q] [-v] [-V] {banner,config,install,inventory,shell} ...
|
||||
|
||||
cdist banner [-h] [-v]
|
||||
cdist banner [-h] [-q] [-v]
|
||||
|
||||
cdist config [-h] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR]
|
||||
cdist config [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR]
|
||||
[-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH]
|
||||
[--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC]
|
||||
[-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s]
|
||||
[-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY]
|
||||
[--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a]
|
||||
[-f HOSTFILE] [-p] [-s] [-t]
|
||||
[host [host ...]]
|
||||
|
||||
cdist install [-h] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR]
|
||||
cdist install [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR]
|
||||
[-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH]
|
||||
[--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC]
|
||||
[-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s]
|
||||
[-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY]
|
||||
[--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a]
|
||||
[-f HOSTFILE] [-p] [-s] [-t]
|
||||
[host [host ...]]
|
||||
|
||||
cdist shell [-h] [-v] [-s SHELL]
|
||||
cdist inventory [-h] [-q] [-v] [-b] [-I INVENTORY_DIR]
|
||||
{add-host,add-tag,del-host,del-tag,list} ...
|
||||
|
||||
cdist inventory add-host [-h] [-q] [-v] [-b] [-I INVENTORY_DIR]
|
||||
[-f HOSTFILE]
|
||||
[host [host ...]]
|
||||
|
||||
cdist inventory add-tag [-h] [-q] [-v] [-b] [-I INVENTORY_DIR]
|
||||
[-f HOSTFILE] [-T TAGFILE] [-t TAGLIST]
|
||||
[host [host ...]]
|
||||
|
||||
cdist inventory del-host [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] [-a]
|
||||
[-f HOSTFILE]
|
||||
[host [host ...]]
|
||||
|
||||
cdist inventory del-tag [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] [-a]
|
||||
[-f HOSTFILE] [-T TAGFILE] [-t TAGLIST]
|
||||
[host [host ...]]
|
||||
|
||||
cdist inventory list [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] [-a]
|
||||
[-f HOSTFILE] [-H] [-t]
|
||||
[host [host ...]]
|
||||
|
||||
cdist shell [-h] [-q] [-v] [-s SHELL]
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
|
@ -72,6 +97,15 @@ CONFIG/INSTALL
|
|||
--------------
|
||||
Configure/install one or more hosts.
|
||||
|
||||
.. option:: -A, --all-tagged
|
||||
|
||||
use all hosts present in tags db
|
||||
|
||||
.. option:: -a, --all
|
||||
|
||||
list hosts that have all specified tags, if -t/--tag
|
||||
is specified
|
||||
|
||||
.. option:: -b, --beta
|
||||
|
||||
Enable beta functionality.
|
||||
|
@ -103,6 +137,16 @@ Configure/install one or more hosts.
|
|||
read hosts from stdin. For the file format see
|
||||
:strong:`HOSTFILE FORMAT` below.
|
||||
|
||||
.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR
|
||||
|
||||
Use specified custom inventory directory. Inventory
|
||||
directory is set up by the following rules: if this
|
||||
argument is set then specified directory is used, if
|
||||
CDIST_INVENTORY_DIR env var is set then its value is
|
||||
used, if HOME env var is set then ~/.cdit/inventory is
|
||||
used, otherwise distribution inventory directory is
|
||||
used.
|
||||
|
||||
.. option:: -i MANIFEST, --initial-manifest MANIFEST
|
||||
|
||||
Path to a cdist manifest or - to read from stdin
|
||||
|
@ -125,7 +169,7 @@ Configure/install one or more hosts.
|
|||
|
||||
Operate on multiple hosts in parallel
|
||||
|
||||
.. option:: -r, --remote-out-dir
|
||||
.. option:: -r REMOTE_OUT_PATH, --remote-out-dir REMOTE_OUT_PATH
|
||||
|
||||
Directory to save cdist output in on the target host
|
||||
|
||||
|
@ -141,6 +185,10 @@ Configure/install one or more hosts.
|
|||
|
||||
Command to use for remote execution (should behave like ssh)
|
||||
|
||||
.. option:: -t, --tag
|
||||
|
||||
host is specified by tag, not hostname/address; list
|
||||
all hosts that contain any of specified tags
|
||||
|
||||
HOSTFILE FORMAT
|
||||
~~~~~~~~~~~~~~~
|
||||
|
@ -174,6 +222,246 @@ Resulting path is used to specify cache path subdirectory under which
|
|||
current host cache data are saved.
|
||||
|
||||
|
||||
INVENTORY
|
||||
---------
|
||||
Manage inventory database.
|
||||
Currently in beta with all sub-commands.
|
||||
|
||||
|
||||
INVENTORY ADD-HOST
|
||||
------------------
|
||||
Add host(s) to inventory database.
|
||||
|
||||
.. option:: host
|
||||
|
||||
host(s) to add
|
||||
|
||||
.. option:: -b, --beta
|
||||
|
||||
Enable beta functionalities. Beta functionalities
|
||||
include inventory command with all sub-commands and
|
||||
all options; config sub-command options: -j/--jobs,
|
||||
-t/--tag, -a/--all.
|
||||
|
||||
Can also be enabled using CDIST_BETA env var.
|
||||
|
||||
.. option:: -f HOSTFILE, --file HOSTFILE
|
||||
|
||||
Read additional hosts to add from specified file or
|
||||
from stdin if '-' (each host on separate line). If no
|
||||
host or host file is specified then, by default, read
|
||||
from stdin. Hostfile format is the same as config hostfile format.
|
||||
|
||||
.. option:: -h, --help
|
||||
|
||||
show this help message and exit
|
||||
|
||||
.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR
|
||||
|
||||
Use specified custom inventory directory. Inventory
|
||||
directory is set up by the following rules: if this
|
||||
argument is set then specified directory is used, if
|
||||
CDIST_INVENTORY_DIR env var is set then its value is
|
||||
used, if HOME env var is set then ~/.cdist/inventory is
|
||||
used, otherwise distribution inventory directory is
|
||||
used.
|
||||
|
||||
|
||||
INVENTORY ADD-TAG
|
||||
-----------------
|
||||
Add tag(s) to inventory database.
|
||||
|
||||
.. option:: host
|
||||
|
||||
list of host(s) for which tags are added
|
||||
|
||||
.. option:: -b, --beta
|
||||
|
||||
Enable beta functionalities. Beta functionalities
|
||||
include inventory command with all sub-commands and
|
||||
all options; config sub-command options: -j/--jobs,
|
||||
-t/--tag, -a/--all.
|
||||
|
||||
Can also be enabled using CDIST_BETA env var.
|
||||
|
||||
.. option:: -f HOSTFILE, --file HOSTFILE
|
||||
|
||||
Read additional hosts to add tags from specified file
|
||||
or from stdin if '-' (each host on separate line). If
|
||||
no host or host file is specified then, by default,
|
||||
read from stdin. If no tags/tagfile nor hosts/hostfile
|
||||
are specified then tags are read from stdin and are
|
||||
added to all hosts. Hostfile format is the same as config hostfile format.
|
||||
|
||||
.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR
|
||||
|
||||
Use specified custom inventory directory. Inventory
|
||||
directory is set up by the following rules: if this
|
||||
argument is set then specified directory is used, if
|
||||
CDIST_INVENTORY_DIR env var is set then its value is
|
||||
used, if HOME env var is set then ~/.cdist/inventory is
|
||||
used, otherwise distribution inventory directory is
|
||||
used.
|
||||
|
||||
.. option:: -T TAGFILE, --tag-file TAGFILE
|
||||
|
||||
Read additional tags to add from specified file or
|
||||
from stdin if '-' (each tag on separate line). If no
|
||||
tag or tag file is specified then, by default, read
|
||||
from stdin. If no tags/tagfile nor hosts/hostfile are
|
||||
specified then tags are read from stdin and are added
|
||||
to all hosts. Tagfile format is the same as config hostfile format.
|
||||
|
||||
.. option:: -t TAGLIST, --taglist TAGLIST
|
||||
|
||||
Tag list to be added for specified host(s), comma
|
||||
separated values
|
||||
|
||||
|
||||
INVENTORY DEL-HOST
|
||||
------------------
|
||||
Delete host(s) from inventory database.
|
||||
|
||||
.. option:: host
|
||||
|
||||
host(s) to delete
|
||||
|
||||
.. option:: -a, --all
|
||||
|
||||
Delete all hosts
|
||||
|
||||
.. option:: -b, --beta
|
||||
|
||||
Enable beta functionalities. Beta functionalities
|
||||
include inventory command with all sub-commands and
|
||||
all options; config sub-command options: -j/--jobs,
|
||||
-t/--tag, -a/--all.
|
||||
|
||||
Can also be enabled using CDIST_BETA env var.
|
||||
|
||||
.. option:: -f HOSTFILE, --file HOSTFILE
|
||||
|
||||
Read additional hosts to delete from specified file or
|
||||
from stdin if '-' (each host on separate line). If no
|
||||
host or host file is specified then, by default, read
|
||||
from stdin. Hostfile format is the same as config hostfile format.
|
||||
|
||||
.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR
|
||||
|
||||
Use specified custom inventory directory. Inventory
|
||||
directory is set up by the following rules: if this
|
||||
argument is set then specified directory is used, if
|
||||
CDIST_INVENTORY_DIR env var is set then its value is
|
||||
used, if HOME env var is set then ~/.cdist/inventory is
|
||||
used, otherwise distribution inventory directory is
|
||||
used.
|
||||
|
||||
|
||||
INVENTORY DEL-TAG
|
||||
-----------------
|
||||
Delete tag(s) from inventory database.
|
||||
|
||||
.. option:: host
|
||||
|
||||
list of host(s) for which tags are deleted
|
||||
|
||||
.. option:: -a, --all
|
||||
|
||||
Delete all tags for specified host(s)
|
||||
|
||||
.. option:: -b, --beta
|
||||
|
||||
Enable beta functionalities. Beta functionalities
|
||||
include inventory command with all sub-commands and
|
||||
all options; config sub-command options: -j/--jobs,
|
||||
-t/--tag, -a/--all.
|
||||
|
||||
Can also be enabled using CDIST_BETA env var.
|
||||
|
||||
.. option:: -f HOSTFILE, --file HOSTFILE
|
||||
|
||||
Read additional hosts to delete tags for from
|
||||
specified file or from stdin if '-' (each host on
|
||||
separate line). If no host or host file is specified
|
||||
then, by default, read from stdin. If no tags/tagfile
|
||||
nor hosts/hostfile are specified then tags are read
|
||||
from stdin and are deleted from all hosts. Hostfile
|
||||
format is the same as config hostfile format.
|
||||
|
||||
.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR
|
||||
|
||||
Use specified custom inventory directory. Inventory
|
||||
directory is set up by the following rules: if this
|
||||
argument is set then specified directory is used, if
|
||||
CDIST_INVENTORY_DIR env var is set then its value is
|
||||
used, if HOME env var is set then ~/.cdist/inventory is
|
||||
used, otherwise distribution inventory directory is
|
||||
used.
|
||||
|
||||
.. option:: -T TAGFILE, --tag-file TAGFILE
|
||||
|
||||
Read additional tags from specified file or from stdin
|
||||
if '-' (each tag on separate line). If no tag or tag
|
||||
file is specified then, by default, read from stdin.
|
||||
If no tags/tagfile nor hosts/hostfile are specified
|
||||
then tags are read from stdin and are added to all
|
||||
hosts. Tagfile format is the same as config hostfile format.
|
||||
|
||||
.. option:: -t TAGLIST, --taglist TAGLIST
|
||||
|
||||
Tag list to be deleted for specified host(s), comma
|
||||
separated values
|
||||
|
||||
|
||||
INVENTORY LIST
|
||||
--------------
|
||||
List inventory database.
|
||||
|
||||
.. option:: host
|
||||
|
||||
host(s) to list
|
||||
|
||||
.. option:: -a, --all
|
||||
|
||||
list hosts that have all specified tags, if -t/--tag
|
||||
is specified
|
||||
|
||||
.. option:: -b, --beta
|
||||
|
||||
Enable beta functionalities. Beta functionalities
|
||||
include inventory command with all sub-commands and
|
||||
all options; config sub-command options: -j/--jobs,
|
||||
-t/--tag, -a/--all.
|
||||
|
||||
Can also be enabled using CDIST_BETA env var.
|
||||
|
||||
.. option:: -f HOSTFILE, --file HOSTFILE
|
||||
|
||||
Read additional hosts to list from specified file or
|
||||
from stdin if '-' (each host on separate line). If no
|
||||
host or host file is specified then, by default, list
|
||||
all. Hostfile format is the same as config hostfile format.
|
||||
|
||||
.. option:: -H, --host-only
|
||||
|
||||
Suppress tags listing
|
||||
|
||||
.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR
|
||||
|
||||
Use specified custom inventory directory. Inventory
|
||||
directory is set up by the following rules: if this
|
||||
argument is set then specified directory is used, if
|
||||
CDIST_INVENTORY_DIR env var is set then its value is
|
||||
used, if HOME env var is set then ~/.cdist/inventory is
|
||||
used, otherwise distribution inventory directory is
|
||||
used.
|
||||
|
||||
.. option:: -t, --tag
|
||||
|
||||
host is specified by tag, not hostname/address; list
|
||||
all hosts that contain any of specified tags
|
||||
|
||||
|
||||
SHELL
|
||||
-----
|
||||
This command allows you to spawn a shell that enables access
|
||||
|
@ -186,14 +474,21 @@ usage. Its primary use is for debugging type parameters.
|
|||
Select shell to use, defaults to current shell. Used shell should
|
||||
be POSIX compatible shell.
|
||||
|
||||
|
||||
FILES
|
||||
-----
|
||||
~/.cdist
|
||||
Your personal cdist config directory. If exists it will be
|
||||
automatically used.
|
||||
~/.cdist/inventory
|
||||
The home inventory directory. If ~/.cdist exists it will be used as
|
||||
default inventory directory.
|
||||
cdist/conf
|
||||
The distribution configuration directory. It contains official types and
|
||||
explorers. This path is relative to cdist installation directory.
|
||||
cdist/inventory
|
||||
The distribution inventory directory.
|
||||
This path is relative to cdist installation directory.
|
||||
|
||||
NOTES
|
||||
-----
|
||||
|
@ -243,6 +538,43 @@ EXAMPLES
|
|||
# Install ikq05.ethz.ch with debug enabled
|
||||
% cdist install -vvv ikq05.ethz.ch
|
||||
|
||||
# List inventory content
|
||||
% cdist inventory list -b
|
||||
|
||||
# List inventory for specified host localhost
|
||||
% cdist inventory list -b localhost
|
||||
|
||||
# List inventory for specified tag loadbalancer
|
||||
% cdist inventory list -b -t loadbalancer
|
||||
|
||||
# Add hosts to inventory
|
||||
% cdist inventory add-host -b web1 web2 web3
|
||||
|
||||
# Delete hosts from file old-hosts from inventory
|
||||
% cdist inventory del-host -b -f old-hosts
|
||||
|
||||
# Add tags to specifed hosts
|
||||
% cdist inventory add-tag -b -t europe,croatia,web,static web1 web2
|
||||
|
||||
# Add tag to all hosts in inventory
|
||||
% cdist inventory add-tag -b -t vm
|
||||
|
||||
# Delete all tags from specified host
|
||||
% cdist inventory del-tag -b -a localhost
|
||||
|
||||
# Delete tags read from stdin from hosts specified by file hosts
|
||||
% cdist inventory del-tag -b -T - -f hosts
|
||||
|
||||
# Configure hosts from inventory with any of specified tags
|
||||
% cdist config -b -t web dynamic
|
||||
|
||||
# Configure hosts from inventory with all specified tags
|
||||
% cdist config -b -t -a web dynamic
|
||||
|
||||
# Configure all hosts from inventory db
|
||||
$ cdist config -b -A
|
||||
|
||||
|
||||
ENVIRONMENT
|
||||
-----------
|
||||
TMPDIR, TEMP, TMP
|
||||
|
@ -272,6 +604,9 @@ CDIST_REMOTE_EXEC
|
|||
CDIST_REMOTE_COPY
|
||||
Use this command for remote copy (should behave like scp).
|
||||
|
||||
CDIST_INVENTORY_DIR
|
||||
Use this directory as inventory directory.
|
||||
|
||||
CDIST_BETA
|
||||
Enable beta functionality.
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ def commandline():
|
|||
import cdist.config
|
||||
import cdist.install
|
||||
import cdist.shell
|
||||
import cdist.inventory
|
||||
import shutil
|
||||
import os
|
||||
|
||||
|
|
Loading…
Reference in a new issue