Merge inventory from beta branch.
This commit is contained in:
		
					parent
					
						
							
								2b6177c9f7
							
						
					
				
			
			
				commit
				
					
						e2a1519332
					
				
			
		
					 28 changed files with 1769 additions and 36 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']])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -134,11 +137,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))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -147,11 +181,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)
 | 
			
		||||
| 
						 | 
				
			
			@ -199,7 +234,8 @@ class Config(object):
 | 
			
		|||
        return (remote_exec, remote_copy, )
 | 
			
		||||
 | 
			
		||||
    @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)
 | 
			
		||||
| 
						 | 
				
			
			@ -216,6 +252,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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,15 +30,44 @@ _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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,10 @@ Changelog
 | 
			
		|||
---------
 | 
			
		||||
 | 
			
		||||
next:
 | 
			
		||||
	* Core: Add inventory functionality (Darko Poljak)
 | 
			
		||||
	* Core: Expose inventory host tags in __target_host_tags env var (Darko Poljak)
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ Contents:
 | 
			
		|||
   cdist-explorer
 | 
			
		||||
   cdist-messaging
 | 
			
		||||
   cdist-parallelization
 | 
			
		||||
   cdist-inventory
 | 
			
		||||
   cdist-reference
 | 
			
		||||
   cdist-best-practice
 | 
			
		||||
   cdist-stages
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,20 +11,45 @@ SYNOPSIS
 | 
			
		|||
 | 
			
		||||
::
 | 
			
		||||
 | 
			
		||||
    cdist [-h] [-q] [-v] [-V] {banner,config,shell,install} ...
 | 
			
		||||
    cdist [-h] [-q] [-v] [-V] {banner,config,install,inventory,shell} ...
 | 
			
		||||
 | 
			
		||||
    cdist banner [-h] [-q] [-v]
 | 
			
		||||
 | 
			
		||||
    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] [-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 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]
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue