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 | # Ignore cdist cache for version control | ||||||
| /cache/ | /cache/ | ||||||
| 
 | 
 | ||||||
|  | # Ignore inventory basedir | ||||||
|  | cdist/inventory/ | ||||||
|  | 
 | ||||||
| # Python: cache, distutils, distribution in general | # Python: cache, distutils, distribution in general | ||||||
| __pycache__/ | __pycache__/ | ||||||
| *.pyc | *.pyc | ||||||
|  |  | ||||||
|  | @ -7,10 +7,10 @@ import collections | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # set of beta sub-commands | # set of beta sub-commands | ||||||
| BETA_COMMANDS = set(('install', )) | BETA_COMMANDS = set(('install', 'inventory', )) | ||||||
| # set of beta arguments for sub-commands | # set of beta arguments for sub-commands | ||||||
| BETA_ARGS = { | BETA_ARGS = { | ||||||
|     'config': set(('jobs', )), |     'config': set(('jobs', 'tag', 'all_tagged_hosts', )), | ||||||
| } | } | ||||||
| EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/" | EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/" | ||||||
| # Parser others can reuse | # Parser others can reuse | ||||||
|  | @ -121,6 +121,17 @@ def get_parsers(): | ||||||
|             'banner', parents=[parser['loglevel']]) |             'banner', parents=[parser['loglevel']]) | ||||||
|     parser['banner'].set_defaults(func=cdist.banner.banner) |     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 |     # Config | ||||||
|     parser['config_main'] = argparse.ArgumentParser(add_help=False) |     parser['config_main'] = argparse.ArgumentParser(add_help=False) | ||||||
|     parser['config_main'].add_argument( |     parser['config_main'].add_argument( | ||||||
|  | @ -156,6 +167,10 @@ def get_parsers(): | ||||||
|     # remote-copy and remote-exec defaults are environment variables |     # remote-copy and remote-exec defaults are environment variables | ||||||
|     # if set; if not then None - these will be futher handled after |     # if set; if not then None - these will be futher handled after | ||||||
|     # parsing to determine implementation default |     # parsing to determine implementation default | ||||||
|  |     parser['config_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( |     parser['config_main'].add_argument( | ||||||
|            '--remote-copy', |            '--remote-copy', | ||||||
|            help='Command to use for remote copy (should behave like scp)', |            help='Command to use for remote copy (should behave like scp)', | ||||||
|  | @ -170,6 +185,15 @@ def get_parsers(): | ||||||
| 
 | 
 | ||||||
|     # Config |     # Config | ||||||
|     parser['config_args'] = argparse.ArgumentParser(add_help=False) |     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( |     parser['config_args'].add_argument( | ||||||
|             'host', nargs='*', help='host(s) to operate on') |             'host', nargs='*', help='host(s) to operate on') | ||||||
|     parser['config_args'].add_argument( |     parser['config_args'].add_argument( | ||||||
|  | @ -183,17 +207,19 @@ def get_parsers(): | ||||||
|            '-p', '--parallel', |            '-p', '--parallel', | ||||||
|            help='operate on multiple hosts in parallel', |            help='operate on multiple hosts in parallel', | ||||||
|            action='store_true', dest='parallel') |            action='store_true', dest='parallel') | ||||||
|     parser['config_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( |     parser['config_args'].add_argument( | ||||||
|            '-s', '--sequential', |            '-s', '--sequential', | ||||||
|            help='operate on multiple hosts sequentially (default)', |            help='operate on multiple hosts sequentially (default)', | ||||||
|            action='store_false', dest='parallel') |            action='store_false', dest='parallel') | ||||||
|  |     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( |     parser['config'] = parser['sub'].add_parser( | ||||||
|             'config', parents=[parser['loglevel'], parser['beta'], |             'config', parents=[parser['loglevel'], parser['beta'], | ||||||
|                                parser['config_main'], |                                parser['config_main'], | ||||||
|  |                                parser['inventory_common'], | ||||||
|                                parser['config_args']]) |                                parser['config_args']]) | ||||||
|     parser['config'].set_defaults(func=cdist.config.Config.commandline) |     parser['config'].set_defaults(func=cdist.config.Config.commandline) | ||||||
| 
 | 
 | ||||||
|  | @ -202,6 +228,134 @@ def get_parsers(): | ||||||
|                                                  parents=[parser['config']]) |                                                  parents=[parser['config']]) | ||||||
|     parser['install'].set_defaults(func=cdist.install.Install.commandline) |     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 |     # Shell | ||||||
|     parser['shell'] = parser['sub'].add_parser( |     parser['shell'] = parser['sub'].add_parser( | ||||||
|             'shell', parents=[parser['loglevel']]) |             'shell', parents=[parser['loglevel']]) | ||||||
|  |  | ||||||
|  | @ -17,9 +17,9 @@ REQUIRED PARAMETERS | ||||||
| uri | uri | ||||||
|    The uri from which to fetch the tarball. |    The uri from which to fetch the tarball. | ||||||
|    Can be anything understood by curl, e.g: |    Can be anything understood by curl, e.g: | ||||||
|      | http://path/to/stage.tgz |        | http://path/to/stage.tgz | ||||||
|      | tftp:///path/to/stage.tgz |        | tftp:///path/to/stage.tgz | ||||||
|      | file:///local/path/stage.tgz |        | file:///local/path/stage.tgz | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| OPTIONAL PARAMETERS | OPTIONAL PARAMETERS | ||||||
|  |  | ||||||
|  | @ -38,6 +38,9 @@ import cdist.hostsource | ||||||
| 
 | 
 | ||||||
| import cdist.exec.local | import cdist.exec.local | ||||||
| import cdist.exec.remote | import cdist.exec.remote | ||||||
|  | 
 | ||||||
|  | from cdist import inventory | ||||||
|  | 
 | ||||||
| import cdist.util.ipaddr as ipaddr | import cdist.util.ipaddr as ipaddr | ||||||
| 
 | 
 | ||||||
| from cdist import core | from cdist import core | ||||||
|  | @ -134,11 +137,42 @@ class Config(object): | ||||||
|         base_root_path = cls.create_base_root_path(args.out_path) |         base_root_path = cls.create_base_root_path(args.out_path) | ||||||
| 
 | 
 | ||||||
|         hostcnt = 0 |         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_path, hostdir = cls.create_host_base_dirs( | ||||||
|                 host, base_root_path) |                 host, base_root_path) | ||||||
| 
 |  | ||||||
|             log.debug("Base root path for target host \"{}\" is \"{}\"".format( |             log.debug("Base root path for target host \"{}\" is \"{}\"".format( | ||||||
|                 host, host_base_path)) |                 host, host_base_path)) | ||||||
| 
 | 
 | ||||||
|  | @ -147,11 +181,12 @@ class Config(object): | ||||||
|                 log.trace("Creating child process for %s", host) |                 log.trace("Creating child process for %s", host) | ||||||
|                 process[host] = multiprocessing.Process( |                 process[host] = multiprocessing.Process( | ||||||
|                         target=cls.onehost, |                         target=cls.onehost, | ||||||
|                         args=(host, host_base_path, hostdir, args, True)) |                         args=(host, host_tags, host_base_path, hostdir, args, | ||||||
|  |                               True)) | ||||||
|                 process[host].start() |                 process[host].start() | ||||||
|             else: |             else: | ||||||
|                 try: |                 try: | ||||||
|                     cls.onehost(host, host_base_path, hostdir, |                     cls.onehost(host, host_tags, host_base_path, hostdir, | ||||||
|                                 args, parallel=False) |                                 args, parallel=False) | ||||||
|                 except cdist.Error as e: |                 except cdist.Error as e: | ||||||
|                     failed_hosts.append(host) |                     failed_hosts.append(host) | ||||||
|  | @ -199,7 +234,8 @@ class Config(object): | ||||||
|         return (remote_exec, remote_copy, ) |         return (remote_exec, remote_copy, ) | ||||||
| 
 | 
 | ||||||
|     @classmethod |     @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""" |         """Configure ONE system""" | ||||||
| 
 | 
 | ||||||
|         log = logging.getLogger(host) |         log = logging.getLogger(host) | ||||||
|  | @ -216,6 +252,7 @@ class Config(object): | ||||||
| 
 | 
 | ||||||
|             local = cdist.exec.local.Local( |             local = cdist.exec.local.Local( | ||||||
|                 target_host=target_host, |                 target_host=target_host, | ||||||
|  |                 target_host_tags=host_tags, | ||||||
|                 base_root_path=host_base_path, |                 base_root_path=host_base_path, | ||||||
|                 host_dir_name=host_dir_name, |                 host_dir_name=host_dir_name, | ||||||
|                 initial_manifest=args.manifest, |                 initial_manifest=args.manifest, | ||||||
|  |  | ||||||
|  | @ -56,6 +56,7 @@ gencode-local | ||||||
|         __object_fq: full qualified object id, iow: $type.name + / + object_id |         __object_fq: full qualified object id, iow: $type.name + / + object_id | ||||||
|         __type: full qualified path to the type's dir |         __type: full qualified path to the type's dir | ||||||
|         __files: full qualified path to the files 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 |     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 |         __object_fq: full qualified object id, iow: $type.name + / + object_id | ||||||
|         __type: full qualified path to the type's dir |         __type: full qualified path to the type's dir | ||||||
|         __files: full qualified path to the files 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 |     returns: string containing the generated code or None | ||||||
| 
 | 
 | ||||||
|  | @ -106,6 +108,7 @@ class Code(object): | ||||||
|             '__target_fqdn': self.target_host[2], |             '__target_fqdn': self.target_host[2], | ||||||
|             '__global': self.local.base_path, |             '__global': self.local.base_path, | ||||||
|             '__files': self.local.files_path, |             '__files': self.local.files_path, | ||||||
|  |             '__target_host_tags': self.local.target_host_tags, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     def _run_gencode(self, cdist_object, which): |     def _run_gencode(self, cdist_object, which): | ||||||
|  |  | ||||||
|  | @ -77,6 +77,7 @@ class Explorer(object): | ||||||
|             '__target_hostname': self.target_host[1], |             '__target_hostname': self.target_host[1], | ||||||
|             '__target_fqdn': self.target_host[2], |             '__target_fqdn': self.target_host[2], | ||||||
|             '__explorer': self.remote.global_explorer_path, |             '__explorer': self.remote.global_explorer_path, | ||||||
|  |             '__target_host_tags': self.local.target_host_tags, | ||||||
|         } |         } | ||||||
|         self._type_explorers_transferred = [] |         self._type_explorers_transferred = [] | ||||||
|         self.jobs = jobs |         self.jobs = jobs | ||||||
|  |  | ||||||
|  | @ -42,6 +42,7 @@ common: | ||||||
|                                 types are defined for use in type emulator |                                 types are defined for use in type emulator | ||||||
|             == local.type_path |             == local.type_path | ||||||
|         __files: full qualified path to the files dir |         __files: full qualified path to the files dir | ||||||
|  |         __target_host_tags: comma spearated list of host tags | ||||||
| 
 | 
 | ||||||
| initial manifest is: | initial manifest is: | ||||||
|     script: full qualified path to the initial manifest |     script: full qualified path to the initial manifest | ||||||
|  | @ -109,6 +110,7 @@ class Manifest(object): | ||||||
|             '__target_hostname': self.target_host[1], |             '__target_hostname': self.target_host[1], | ||||||
|             '__target_fqdn': self.target_host[2], |             '__target_fqdn': self.target_host[2], | ||||||
|             '__files': self.local.files_path, |             '__files': self.local.files_path, | ||||||
|  |             '__target_host_tags': self.local.target_host_tags, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if self.log.getEffectiveLevel() == logging.DEBUG: |         if self.log.getEffectiveLevel() == logging.DEBUG: | ||||||
|  |  | ||||||
|  | @ -49,6 +49,7 @@ class Local(object): | ||||||
|     """ |     """ | ||||||
|     def __init__(self, |     def __init__(self, | ||||||
|                  target_host, |                  target_host, | ||||||
|  |                  target_host_tags, | ||||||
|                  base_root_path, |                  base_root_path, | ||||||
|                  host_dir_name, |                  host_dir_name, | ||||||
|                  exec_path=sys.argv[0], |                  exec_path=sys.argv[0], | ||||||
|  | @ -58,6 +59,10 @@ class Local(object): | ||||||
|                  quiet_mode=False): |                  quiet_mode=False): | ||||||
| 
 | 
 | ||||||
|         self.target_host = target_host |         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.hostdir = host_dir_name | ||||||
|         self.base_path = os.path.join(base_root_path, "data") |         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", | ||||||
|             "cdist-shell-no-target-host", |             "cdist-shell-no-target-host", | ||||||
|         ) |         ) | ||||||
|  |         self.target_host_tags = "" | ||||||
| 
 | 
 | ||||||
|         host_dir_name = cdist.str_hash(self.target_host[0]) |         host_dir_name = cdist.str_hash(self.target_host[0]) | ||||||
|         base_root_path = tempfile.mkdtemp() |         base_root_path = tempfile.mkdtemp() | ||||||
|  | @ -51,6 +52,7 @@ class Shell(object): | ||||||
| 
 | 
 | ||||||
|         self.local = cdist.exec.local.Local( |         self.local = cdist.exec.local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=host_base_path, |             base_root_path=host_base_path, | ||||||
|             host_dir_name=host_dir_name) |             host_dir_name=host_dir_name) | ||||||
| 
 | 
 | ||||||
|  | @ -77,6 +79,7 @@ class Shell(object): | ||||||
|             '__manifest': self.local.manifest_path, |             '__manifest': self.local.manifest_path, | ||||||
|             '__explorer': self.local.global_explorer_path, |             '__explorer': self.local.global_explorer_path, | ||||||
|             '__files': self.local.files_path, |             '__files': self.local.files_path, | ||||||
|  |             '__target_host_tags': self.local.target_host_tags, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         self.env.update(additional_env) |         self.env.update(additional_env) | ||||||
|  |  | ||||||
|  | @ -42,6 +42,7 @@ class CdistTestCase(unittest.TestCase): | ||||||
|         'cdisttesthost', |         'cdisttesthost', | ||||||
|         'cdisttesthost', |         'cdisttesthost', | ||||||
|     ) |     ) | ||||||
|  |     target_host_tags = "tag1,tag2,tag3" | ||||||
| 
 | 
 | ||||||
|     def mkdtemp(self, **kwargs): |     def mkdtemp(self, **kwargs): | ||||||
|         return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) |         return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) | ||||||
|  |  | ||||||
|  | @ -46,6 +46,7 @@ class CodeTestCase(test.CdistTestCase): | ||||||
| 
 | 
 | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=self.host_base_path, |             base_root_path=self.host_base_path, | ||||||
|             host_dir_name=self.hostdir, |             host_dir_name=self.hostdir, | ||||||
|             exec_path=cdist.test.cdist_exec_path, |             exec_path=cdist.test.cdist_exec_path, | ||||||
|  | @ -97,6 +98,8 @@ class CodeTestCase(test.CdistTestCase): | ||||||
|                          self.cdist_object.object_id) |                          self.cdist_object.object_id) | ||||||
|         self.assertEqual(output_dict['__object_name'], self.cdist_object.name) |         self.assertEqual(output_dict['__object_name'], self.cdist_object.name) | ||||||
|         self.assertEqual(output_dict['__files'], self.local.files_path) |         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): |     def test_run_gencode_remote_environment(self): | ||||||
|         output_string = self.code.run_gencode_remote(self.cdist_object) |         output_string = self.code.run_gencode_remote(self.cdist_object) | ||||||
|  | @ -120,6 +123,8 @@ class CodeTestCase(test.CdistTestCase): | ||||||
|                          self.cdist_object.object_id) |                          self.cdist_object.object_id) | ||||||
|         self.assertEqual(output_dict['__object_name'], self.cdist_object.name) |         self.assertEqual(output_dict['__object_name'], self.cdist_object.name) | ||||||
|         self.assertEqual(output_dict['__files'], self.local.files_path) |         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): |     def test_transfer_code_remote(self): | ||||||
|         self.cdist_object.code_remote = self.code.run_gencode_remote( |         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_id: $__object_id" | ||||||
| echo "echo __object_name: $__object_name" | echo "echo __object_name: $__object_name" | ||||||
| echo "echo __files: $__files" | 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) |         os.makedirs(self.host_base_path) | ||||||
|         self.local = cdist.exec.local.Local( |         self.local = cdist.exec.local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=self.host_base_path, |             base_root_path=self.host_base_path, | ||||||
|             host_dir_name=self.hostdir) |             host_dir_name=self.hostdir) | ||||||
| 
 | 
 | ||||||
|  | @ -164,6 +165,7 @@ class ConfigRunTestCase(test.CdistTestCase): | ||||||
|         """Test if the dryrun option is working like expected""" |         """Test if the dryrun option is working like expected""" | ||||||
|         drylocal = cdist.exec.local.Local( |         drylocal = cdist.exec.local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=self.host_base_path, |             base_root_path=self.host_base_path, | ||||||
|             host_dir_name=self.hostdir, |             host_dir_name=self.hostdir, | ||||||
|             # exec_path can not derivated from sys.argv in case of unittest |             # exec_path can not derivated from sys.argv in case of unittest | ||||||
|  | @ -181,6 +183,7 @@ class ConfigRunTestCase(test.CdistTestCase): | ||||||
|         """Test to show dependency resolver warning message.""" |         """Test to show dependency resolver warning message.""" | ||||||
|         local = cdist.exec.local.Local( |         local = cdist.exec.local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=self.host_base_path, |             base_root_path=self.host_base_path, | ||||||
|             host_dir_name=self.hostdir, |             host_dir_name=self.hostdir, | ||||||
|             exec_path=os.path.abspath(os.path.join( |             exec_path=os.path.abspath(os.path.join( | ||||||
|  |  | ||||||
|  | @ -53,6 +53,7 @@ class EmulatorTestCase(test.CdistTestCase): | ||||||
| 
 | 
 | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=host_base_path, |             base_root_path=host_base_path, | ||||||
|             host_dir_name=hostdir, |             host_dir_name=hostdir, | ||||||
|             exec_path=test.cdist_exec_path, |             exec_path=test.cdist_exec_path, | ||||||
|  | @ -156,6 +157,7 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): | ||||||
| 
 | 
 | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=host_base_path, |             base_root_path=host_base_path, | ||||||
|             host_dir_name=hostdir, |             host_dir_name=hostdir, | ||||||
|             exec_path=test.cdist_exec_path, |             exec_path=test.cdist_exec_path, | ||||||
|  | @ -246,6 +248,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): | ||||||
| 
 | 
 | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=host_base_path, |             base_root_path=host_base_path, | ||||||
|             host_dir_name=hostdir, |             host_dir_name=hostdir, | ||||||
|             exec_path=test.cdist_exec_path, |             exec_path=test.cdist_exec_path, | ||||||
|  | @ -279,6 +282,7 @@ class OverrideTestCase(test.CdistTestCase): | ||||||
| 
 | 
 | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=host_base_path, |             base_root_path=host_base_path, | ||||||
|             host_dir_name=hostdir, |             host_dir_name=hostdir, | ||||||
|             exec_path=test.cdist_exec_path, |             exec_path=test.cdist_exec_path, | ||||||
|  | @ -322,6 +326,7 @@ class ArgumentsTestCase(test.CdistTestCase): | ||||||
| 
 | 
 | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=host_base_path, |             base_root_path=host_base_path, | ||||||
|             host_dir_name=hostdir, |             host_dir_name=hostdir, | ||||||
|             exec_path=test.cdist_exec_path, |             exec_path=test.cdist_exec_path, | ||||||
|  | @ -445,6 +450,7 @@ class StdinTestCase(test.CdistTestCase): | ||||||
| 
 | 
 | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=host_base_path, |             base_root_path=host_base_path, | ||||||
|             host_dir_name=hostdir, |             host_dir_name=hostdir, | ||||||
|             exec_path=test.cdist_exec_path, |             exec_path=test.cdist_exec_path, | ||||||
|  | @ -511,6 +517,7 @@ class EmulatorAlreadyExistingRequirementsWarnTestCase(test.CdistTestCase): | ||||||
| 
 | 
 | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=host_base_path, |             base_root_path=host_base_path, | ||||||
|             host_dir_name=hostdir, |             host_dir_name=hostdir, | ||||||
|             exec_path=test.cdist_exec_path, |             exec_path=test.cdist_exec_path, | ||||||
|  |  | ||||||
|  | @ -50,6 +50,7 @@ class ExplorerClassTestCase(test.CdistTestCase): | ||||||
| 
 | 
 | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=base_root_path, |             base_root_path=base_root_path, | ||||||
|             host_dir_name=hostdir, |             host_dir_name=hostdir, | ||||||
|             exec_path=test.cdist_exec_path, |             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) |         base_root_path = os.path.join(out_path, hostdir) | ||||||
|         self.local = local.Local( |         self.local = local.Local( | ||||||
|             target_host=self.target_host, |             target_host=self.target_host, | ||||||
|  |             target_host_tags=self.target_host_tags, | ||||||
|             base_root_path=base_root_path, |             base_root_path=base_root_path, | ||||||
|             host_dir_name=hostdir, |             host_dir_name=hostdir, | ||||||
|             exec_path=cdist.test.cdist_exec_path, |             exec_path=cdist.test.cdist_exec_path, | ||||||
|  | @ -93,6 +94,8 @@ class ManifestTestCase(test.CdistTestCase): | ||||||
|                          self.local.type_path) |                          self.local.type_path) | ||||||
|         self.assertEqual(output_dict['__manifest'], self.local.manifest_path) |         self.assertEqual(output_dict['__manifest'], self.local.manifest_path) | ||||||
|         self.assertEqual(output_dict['__files'], self.local.files_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): |     def test_type_manifest_environment(self): | ||||||
|         cdist_type = core.CdistType(self.local.type_path, '__dump_environment') |         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_id'], cdist_object.object_id) | ||||||
|         self.assertEqual(output_dict['__object_name'], cdist_object.name) |         self.assertEqual(output_dict['__object_name'], cdist_object.name) | ||||||
|         self.assertEqual(output_dict['__files'], self.local.files_path) |         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): |     def test_debug_env_setup(self): | ||||||
|         current_level = self.log.getEffectiveLevel() |         current_level = self.log.getEffectiveLevel() | ||||||
|  |  | ||||||
|  | @ -9,4 +9,5 @@ __global: $__global | ||||||
| __cdist_type_base_path: $__cdist_type_base_path | __cdist_type_base_path: $__cdist_type_base_path | ||||||
| __manifest: $__manifest | __manifest: $__manifest | ||||||
| __files: $__files | __files: $__files | ||||||
|  | __target_host_tags: $__target_host_tags | ||||||
| DONE | DONE | ||||||
|  |  | ||||||
|  | @ -13,4 +13,5 @@ __object: $__object | ||||||
| __object_id: $__object_id | __object_id: $__object_id | ||||||
| __object_name: $__object_name | __object_name: $__object_name | ||||||
| __files: $__files | __files: $__files | ||||||
|  | __target_host_tags: $__target_host_tags | ||||||
| DONE | DONE | ||||||
|  |  | ||||||
|  | @ -5,8 +5,8 @@ _cdist() | ||||||
|     cur="${COMP_WORDS[COMP_CWORD]}" |     cur="${COMP_WORDS[COMP_CWORD]}" | ||||||
|     prev="${COMP_WORDS[COMP_CWORD-1]}" |     prev="${COMP_WORDS[COMP_CWORD-1]}" | ||||||
|     prevprev="${COMP_WORDS[COMP_CWORD-2]}" |     prevprev="${COMP_WORDS[COMP_CWORD-2]}" | ||||||
|     opts="-h --help -d --debug -v --verbose -V --version" |     opts="-h --help -q --quiet -v --verbose -V --version" | ||||||
|     cmds="banner shell config install" |     cmds="banner config install inventory shell" | ||||||
| 
 | 
 | ||||||
|     case "${prevprev}" in |     case "${prevprev}" in | ||||||
|         shell) |         shell) | ||||||
|  | @ -18,6 +18,41 @@ _cdist() | ||||||
|                     ;; |                     ;; | ||||||
|             esac |             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 |     esac | ||||||
| 
 | 
 | ||||||
|     case "${prev}" in |     case "${prev}" in | ||||||
|  | @ -26,23 +61,31 @@ _cdist() | ||||||
|             return 0 |             return 0 | ||||||
|             ;; |             ;; | ||||||
|         banner) |         banner) | ||||||
|             opts="-h --help -d --debug -v --verbose" |             opts="-h --help -q --quiet -v --verbose" | ||||||
|             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) |             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) | ||||||
|             return 0 |             return 0 | ||||||
|             ;; |             ;; | ||||||
|         shell) |         shell) | ||||||
|             opts="-h --help -d --debug -v --verbose -s --shell" |             opts="-h --help -q --quiet -v --verbose -s --shell" | ||||||
|             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) |             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) | ||||||
|             return 0 |             return 0 | ||||||
|             ;; |             ;; | ||||||
|         config|install) |         config|install) | ||||||
|             opts="-h --help -d --debug -v --verbose -b --beta \ |             opts="-h --help -q --quiet -v --verbose -b --beta \ | ||||||
|                 -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs \ |                 -I --inventory -C --cache-path-pattern -c --conf-dir \ | ||||||
|                 -n --dry-run -o --out-dir -p --parallel -r --remote-out-dir -s --sequential \ |                 -f --file -i --initial-manifest -A --all-tagged \ | ||||||
|                 --remote-copy --remote-exec" |                 -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}) ) |             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) | ||||||
|             return 0 |             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 |     esac | ||||||
|  |  | ||||||
|  | @ -11,16 +11,16 @@ _cdist() | ||||||
| 
 | 
 | ||||||
|     case $state in |     case $state in | ||||||
|         opts_cmds) |         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 |             case $words[2] in | ||||||
|                 -*) |                 -*) | ||||||
|                     opts=(-h --help -d --debug -v --verbose -V --version) |                     opts=(-h --help -q --quiet -v --verbose -V --version) | ||||||
|                     compadd "$@" -- $opts |                     compadd "$@" -- $opts | ||||||
|                     ;; |                     ;; | ||||||
|                 banner) |                 banner) | ||||||
|                     opts=(-h --help -d --debug -v --verbose) |                     opts=(-h --help -q --quiet -v --verbose) | ||||||
|                     compadd "$@" -- $opts |                     compadd "$@" -- $opts | ||||||
|                     ;; |                     ;; | ||||||
|                 shell) |                 shell) | ||||||
|  | @ -30,16 +30,45 @@ _cdist() | ||||||
|                             compadd "$@" -- $shells |                             compadd "$@" -- $shells | ||||||
|                             ;; |                             ;; | ||||||
|                         *) |                         *) | ||||||
|                             opts=(-h --help -d --debug -v --verbose -s --shell) |                             opts=(-h --help -q --quiet -v --verbose -s --shell) | ||||||
|                             compadd "$@" -- $opts |                             compadd "$@" -- $opts | ||||||
|                             ;; |                             ;; | ||||||
|                     esac |                     esac | ||||||
|                     ;; |                     ;; | ||||||
|                 config|install) |                 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 |                     compadd "$@" -- $opts | ||||||
|                     ;; |                     ;; | ||||||
|                *) |                 inventory) | ||||||
|  |                     case $words[3] in | ||||||
|  |                         list) | ||||||
|  |                             opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -a --all -f --file -H --host-only -t --tag) | ||||||
|  |                             compadd "$@" -- $opts | ||||||
|  |                             ;; | ||||||
|  |                         add-host) | ||||||
|  |                             opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -f --file) | ||||||
|  |                             compadd "$@" -- $opts | ||||||
|  |                             ;; | ||||||
|  |                         del-host) | ||||||
|  |                             opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -a --all -f --file) | ||||||
|  |                             compadd "$@" -- $opts | ||||||
|  |                             ;; | ||||||
|  |                         add-tag) | ||||||
|  |                             opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -f --file -T --tag-file -t --taglist) | ||||||
|  |                             compadd "$@" -- $opts | ||||||
|  |                             ;; | ||||||
|  |                         del-tag) | ||||||
|  |                             opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -a --all -f --file -T --tag-file -t --taglist) | ||||||
|  |                             compadd "$@" -- $opts | ||||||
|  |                             ;; | ||||||
|  |                         *) | ||||||
|  |                             cmds=(list add-host del-host add-tag del-tag) | ||||||
|  |                             opts=(-h --help -q --quiet -v --verbose) | ||||||
|  |                             compadd "$@" -- $cmds $opts | ||||||
|  |                             ;; | ||||||
|  |                     esac | ||||||
|  |                     ;; | ||||||
|  |                 *) | ||||||
|                     ;; |                     ;; | ||||||
|             esac |             esac | ||||||
|     esac |     esac | ||||||
|  |  | ||||||
|  | @ -2,6 +2,10 @@ Changelog | ||||||
| --------- | --------- | ||||||
| 
 | 
 | ||||||
| next: | 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) | 	* Types: Fix install types (Steven Armstrong) | ||||||
| 	* Core: Add -r command line option for setting remote base path (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) | 	* 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. |     The distribution configuration directory. | ||||||
|     This contains types and explorers to be used. |     This contains types and explorers to be used. | ||||||
| 
 | 
 | ||||||
|  | cdist/inventory/ | ||||||
|  |     The distribution inventory directory. | ||||||
|  |     This path is relative to cdist installation directory. | ||||||
|  | 
 | ||||||
| confdir | confdir | ||||||
|     Cdist will use all available configuration directories and create |     Cdist will use all available configuration directories and create | ||||||
|     a temporary confdir containing links to the real configuration directories. |     a temporary confdir containing links to the real configuration directories. | ||||||
|  | @ -239,6 +243,9 @@ __target_fqdn | ||||||
|     This variable is derived from **__target_host** |     This variable is derived from **__target_host** | ||||||
|     (using **socket.getfqdn()**). |     (using **socket.getfqdn()**). | ||||||
|     Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell. |     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 | __type | ||||||
|     Path to the current type. |     Path to the current type. | ||||||
|     Available for: type manifest, type gencode. |     Available for: type manifest, type gencode. | ||||||
|  | @ -274,6 +281,9 @@ CDIST_REMOTE_EXEC | ||||||
| CDIST_REMOTE_COPY | CDIST_REMOTE_COPY | ||||||
|     Use this command for remote copy (should behave like scp). |     Use this command for remote copy (should behave like scp). | ||||||
| 
 | 
 | ||||||
|  | CDIST_INVENTORY_DIR | ||||||
|  |     Use this directory as inventory directory. | ||||||
|  | 
 | ||||||
| CDIST_BETA | CDIST_BETA | ||||||
|     Enable beta functionalities. |     Enable beta functionalities. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ Contents: | ||||||
|    cdist-explorer |    cdist-explorer | ||||||
|    cdist-messaging |    cdist-messaging | ||||||
|    cdist-parallelization |    cdist-parallelization | ||||||
|  |    cdist-inventory | ||||||
|    cdist-reference |    cdist-reference | ||||||
|    cdist-best-practice |    cdist-best-practice | ||||||
|    cdist-stages |    cdist-stages | ||||||
|  |  | ||||||
|  | @ -11,21 +11,46 @@ 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 banner [-h] [-q] [-v] | ||||||
| 
 | 
 | ||||||
|     cdist config [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] |     cdist config [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] | ||||||
|                  [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] |                  [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] | ||||||
|                  [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] |                  [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] | ||||||
|                  [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] |                  [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] | ||||||
|                  [host [host ...]] |                  [-f HOSTFILE] [-p] [-s] [-t] | ||||||
|  |                  [host [host ...]]  | ||||||
| 
 | 
 | ||||||
|     cdist install [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] |     cdist install [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] | ||||||
|                   [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] |                   [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] | ||||||
|                   [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] |                   [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] | ||||||
|                   [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] |                   [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] | ||||||
|                   [host [host ...]] |                   [-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] |     cdist shell [-h] [-q] [-v] [-s SHELL] | ||||||
| 
 | 
 | ||||||
|  | @ -72,6 +97,15 @@ CONFIG/INSTALL | ||||||
| -------------- | -------------- | ||||||
| Configure/install one or more hosts. | 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 | .. option:: -b, --beta | ||||||
| 
 | 
 | ||||||
|     Enable beta functionality. |     Enable beta functionality. | ||||||
|  | @ -103,6 +137,16 @@ Configure/install one or more hosts. | ||||||
|     read hosts from stdin. For the file format see |     read hosts from stdin. For the file format see | ||||||
|     :strong:`HOSTFILE FORMAT` below. |     :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 | .. option:: -i MANIFEST, --initial-manifest MANIFEST | ||||||
| 
 | 
 | ||||||
|     Path to a cdist manifest or - to read from stdin |     Path to a cdist manifest or - to read from stdin | ||||||
|  | @ -141,6 +185,10 @@ Configure/install one or more hosts. | ||||||
| 
 | 
 | ||||||
|     Command to use for remote execution (should behave like ssh) |     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 | HOSTFILE FORMAT | ||||||
| ~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~ | ||||||
|  | @ -174,6 +222,246 @@ Resulting path is used to specify cache path subdirectory under which | ||||||
| current host cache data are saved. | 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 | SHELL | ||||||
| ----- | ----- | ||||||
| This command allows you to spawn a shell that enables access | 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 |     Select shell to use, defaults to current shell. Used shell should | ||||||
|     be POSIX compatible shell. |     be POSIX compatible shell. | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| FILES | FILES | ||||||
| ----- | ----- | ||||||
| ~/.cdist | ~/.cdist | ||||||
|     Your personal cdist config directory. If exists it will be |     Your personal cdist config directory. If exists it will be | ||||||
|     automatically used. |     automatically used. | ||||||
|  | ~/.cdist/inventory | ||||||
|  |     The home inventory directory. If ~/.cdist exists it will be used as | ||||||
|  |     default inventory directory. | ||||||
| cdist/conf | cdist/conf | ||||||
|     The distribution configuration directory. It contains official types and |     The distribution configuration directory. It contains official types and | ||||||
|     explorers. This path is relative to cdist installation directory. |     explorers. This path is relative to cdist installation directory. | ||||||
|  | cdist/inventory | ||||||
|  |     The distribution inventory directory. | ||||||
|  |     This path is relative to cdist installation directory. | ||||||
| 
 | 
 | ||||||
| NOTES | NOTES | ||||||
| ----- | ----- | ||||||
|  | @ -243,6 +538,43 @@ EXAMPLES | ||||||
|     # Install ikq05.ethz.ch with debug enabled |     # Install ikq05.ethz.ch with debug enabled | ||||||
|     % cdist install -vvv ikq05.ethz.ch |     % 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 | ENVIRONMENT | ||||||
| ----------- | ----------- | ||||||
| TMPDIR, TEMP, TMP | TMPDIR, TEMP, TMP | ||||||
|  | @ -272,6 +604,9 @@ CDIST_REMOTE_EXEC | ||||||
| CDIST_REMOTE_COPY | CDIST_REMOTE_COPY | ||||||
|     Use this command for remote copy (should behave like scp). |     Use this command for remote copy (should behave like scp). | ||||||
| 
 | 
 | ||||||
|  | CDIST_INVENTORY_DIR | ||||||
|  |     Use this directory as inventory directory. | ||||||
|  | 
 | ||||||
| CDIST_BETA | CDIST_BETA | ||||||
|     Enable beta functionality. |     Enable beta functionality. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -33,6 +33,7 @@ def commandline(): | ||||||
|     import cdist.config |     import cdist.config | ||||||
|     import cdist.install |     import cdist.install | ||||||
|     import cdist.shell |     import cdist.shell | ||||||
|  |     import cdist.inventory | ||||||
|     import shutil |     import shutil | ||||||
|     import os |     import os | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue