forked from ungleich-public/cdist
		
	Add cdist info command
This commit is contained in:
		
					parent
					
						
							
								72935e0a79
							
						
					
				
			
			
				commit
				
					
						e4596593c0
					
				
			
		
					 5 changed files with 283 additions and 36 deletions
				
			
		|  | @ -6,6 +6,7 @@ import collections | ||||||
| import functools | import functools | ||||||
| import cdist.configuration | import cdist.configuration | ||||||
| import cdist.preos | import cdist.preos | ||||||
|  | import cdist.info | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # set of beta sub-commands | # set of beta sub-commands | ||||||
|  | @ -436,6 +437,37 @@ def get_parsers(): | ||||||
|                   ' should be POSIX compatible shell.')) |                   ' should be POSIX compatible shell.')) | ||||||
|     parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) |     parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) | ||||||
| 
 | 
 | ||||||
|  |     # Info | ||||||
|  |     parser['info'] = parser['sub'].add_parser('info') | ||||||
|  |     parser['info'].add_argument( | ||||||
|  |             '-a', '--all', help='Display all info. This is the default.', | ||||||
|  |             action='store_true', default=False) | ||||||
|  |     parser['info'].add_argument( | ||||||
|  |             '-c', '--conf-dir', | ||||||
|  |             help='Add configuration directory (can be repeated).', | ||||||
|  |             action='append') | ||||||
|  |     parser['info'].add_argument( | ||||||
|  |             '-e', '--global-explorers', | ||||||
|  |             help='Display info for global explorers.', action='store_true', | ||||||
|  |             default=False) | ||||||
|  |     parser['info'].add_argument( | ||||||
|  |             '-F', '--fixed-string', | ||||||
|  |             help='Interpret pattern as a fixed string.', action='store_true', | ||||||
|  |             default=False) | ||||||
|  |     parser['info'].add_argument( | ||||||
|  |             '-f', '--full', help='Display full details.', | ||||||
|  |             action='store_true', default=False) | ||||||
|  |     parser['info'].add_argument( | ||||||
|  |            '-g', '--config-file', | ||||||
|  |            help='Use specified custom configuration file.', | ||||||
|  |            dest="config_file", required=False) | ||||||
|  |     parser['info'].add_argument( | ||||||
|  |             '-t', '--types', help='Display info for types.', | ||||||
|  |             action='store_true', default=False) | ||||||
|  |     parser['info'].add_argument( | ||||||
|  |             'pattern', nargs='?', help='Glob pattern.') | ||||||
|  |     parser['info'].set_defaults(func=cdist.info.Info.commandline) | ||||||
|  | 
 | ||||||
|     for p in parser: |     for p in parser: | ||||||
|         parser[p].epilog = EPILOG |         parser[p].epilog = EPILOG | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -69,7 +69,6 @@ class Local(object): | ||||||
| 
 | 
 | ||||||
|         self.exec_path = exec_path |         self.exec_path = exec_path | ||||||
|         self.custom_initial_manifest = initial_manifest |         self.custom_initial_manifest = initial_manifest | ||||||
|         self._add_conf_dirs = add_conf_dirs |  | ||||||
|         self.cache_path_pattern = cache_path_pattern |         self.cache_path_pattern = cache_path_pattern | ||||||
|         self.quiet_mode = quiet_mode |         self.quiet_mode = quiet_mode | ||||||
|         if configuration: |         if configuration: | ||||||
|  | @ -84,16 +83,7 @@ class Local(object): | ||||||
|         self._init_cache_dir(None) |         self._init_cache_dir(None) | ||||||
|         self._init_paths() |         self._init_paths() | ||||||
|         self._init_object_marker() |         self._init_object_marker() | ||||||
|         self._init_conf_dirs() |         self._init_conf_dirs(add_conf_dirs) | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def dist_conf_dir(self): |  | ||||||
|         return os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), |  | ||||||
|                                             "conf")) |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def home_dir(self): |  | ||||||
|         return cdist.home_dir() |  | ||||||
| 
 | 
 | ||||||
|     def _init_log(self): |     def _init_log(self): | ||||||
|         self.log = logging.getLogger(self.target_host[0]) |         self.log = logging.getLogger(self.target_host[0]) | ||||||
|  | @ -140,28 +130,9 @@ class Local(object): | ||||||
|         # Does not need to be secure - just randomly different from .cdist |         # Does not need to be secure - just randomly different from .cdist | ||||||
|         self.object_marker_name = tempfile.mktemp(prefix='.cdist-', dir='') |         self.object_marker_name = tempfile.mktemp(prefix='.cdist-', dir='') | ||||||
| 
 | 
 | ||||||
|     def _init_conf_dirs(self): |     def _init_conf_dirs(self, add_conf_dirs): | ||||||
|         self.conf_dirs = [] |         self.conf_dirs = util.resolve_conf_dirs( | ||||||
| 
 |             self.configuration, add_conf_dirs=add_conf_dirs) | ||||||
|         self.conf_dirs.append(self.dist_conf_dir) |  | ||||||
| 
 |  | ||||||
|         # Is the default place for user created explorer, type and manifest |  | ||||||
|         if self.home_dir: |  | ||||||
|             self.conf_dirs.append(self.home_dir) |  | ||||||
| 
 |  | ||||||
|         # Add directories defined in the CDIST_PATH environment variable |  | ||||||
|         # if 'CDIST_PATH' in os.environ: |  | ||||||
|         #     cdist_path_dirs = re.split(r'(?<!\\):', os.environ['CDIST_PATH']) |  | ||||||
|         #     cdist_path_dirs.reverse() |  | ||||||
|         #     self.conf_dirs.extend(cdist_path_dirs) |  | ||||||
|         if 'conf_dir' in self.configuration: |  | ||||||
|             conf_dirs = self.configuration['conf_dir'] |  | ||||||
|             if conf_dirs: |  | ||||||
|                 self.conf_dirs.extend(conf_dirs) |  | ||||||
| 
 |  | ||||||
|         # Add command line supplied directories |  | ||||||
|         if self._add_conf_dirs: |  | ||||||
|             self.conf_dirs.extend(self._add_conf_dirs) |  | ||||||
| 
 | 
 | ||||||
|     def _init_directories(self): |     def _init_directories(self): | ||||||
|         self.mkdir(self.conf_path) |         self.mkdir(self.conf_path) | ||||||
|  | @ -187,10 +158,11 @@ class Local(object): | ||||||
|             self.object_marker_name, self.object_marker_file)) |             self.object_marker_name, self.object_marker_file)) | ||||||
| 
 | 
 | ||||||
|     def _init_cache_dir(self, cache_dir): |     def _init_cache_dir(self, cache_dir): | ||||||
|  |         home_dir = cdist.home_dir() | ||||||
|         if cache_dir: |         if cache_dir: | ||||||
|             self.cache_path = cache_dir |             self.cache_path = cache_dir | ||||||
|         elif self.home_dir: |         elif home_dir: | ||||||
|             self.cache_path = os.path.join(self.home_dir, "cache") |             self.cache_path = os.path.join(home_dir, "cache") | ||||||
|         else: |         else: | ||||||
|             raise cdist.Error( |             raise cdist.Error( | ||||||
|                 "No homedir setup and no cache dir location given") |                 "No homedir setup and no cache dir location given") | ||||||
|  |  | ||||||
|  | @ -175,3 +175,28 @@ def log_std_fd(log, command, stdfd, prefix): | ||||||
|         stdfd.seek(0, 0) |         stdfd.seek(0, 0) | ||||||
|         log.trace("Command: {}; {}: {}".format( |         log.trace("Command: {}; {}: {}".format( | ||||||
|             command, prefix, stdfd.read().decode())) |             command, prefix, stdfd.read().decode())) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def dist_conf_dir(): | ||||||
|  |     return os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), | ||||||
|  |                                         "conf")) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def resolve_conf_dirs(configuration, add_conf_dirs): | ||||||
|  |     conf_dirs = [] | ||||||
|  | 
 | ||||||
|  |     conf_dirs.append(dist_conf_dir()) | ||||||
|  | 
 | ||||||
|  |     home_dir = cdist.home_dir() | ||||||
|  |     if home_dir: | ||||||
|  |         conf_dirs.append(home_dir) | ||||||
|  | 
 | ||||||
|  |     if 'conf_dir' in configuration: | ||||||
|  |         x = configuration['conf_dir'] | ||||||
|  |         if x: | ||||||
|  |             conf_dirs.extend(x) | ||||||
|  | 
 | ||||||
|  |     if add_conf_dirs: | ||||||
|  |         conf_dirs.extend(add_conf_dirs) | ||||||
|  |     conf_dirs = set(conf_dirs) | ||||||
|  |     return conf_dirs | ||||||
|  |  | ||||||
							
								
								
									
										183
									
								
								cdist/info.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								cdist/info.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,183 @@ | ||||||
|  | #!/usr/bin/env python3 | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # | ||||||
|  | # 2019-2020 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 cdist.configuration | ||||||
|  | import cdist.core | ||||||
|  | import cdist.exec.util as util | ||||||
|  | import os | ||||||
|  | import glob | ||||||
|  | import fnmatch | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Info(object): | ||||||
|  | 
 | ||||||
|  |     def __init__(self, conf_dirs, args): | ||||||
|  |         self.conf_dirs = conf_dirs | ||||||
|  |         self.all = args.all | ||||||
|  |         self.display_global_explorers = args.global_explorers | ||||||
|  |         self.display_types = args.types | ||||||
|  |         if not self.display_global_explorers and not self.display_types: | ||||||
|  |             self.all = True | ||||||
|  |         self.fixed_string = args.fixed_string | ||||||
|  |         self._setup_glob_pattern(args.pattern) | ||||||
|  |         self.full = args.full | ||||||
|  | 
 | ||||||
|  |     def _setup_glob_pattern(self, pattern): | ||||||
|  |         if pattern is None: | ||||||
|  |             self.glob_pattern = '*' | ||||||
|  |         elif ('?' in pattern or '*' in pattern or '[' in pattern or | ||||||
|  |               self.fixed_string): | ||||||
|  |             self.glob_pattern = pattern | ||||||
|  |         else: | ||||||
|  |             self.glob_pattern = '*' + pattern + '*' | ||||||
|  | 
 | ||||||
|  |     @classmethod | ||||||
|  |     def commandline(cls, args): | ||||||
|  |         cfg = cdist.configuration.Configuration(args) | ||||||
|  |         configuration = cfg.get_config(section='GLOBAL') | ||||||
|  |         conf_dirs = util.resolve_conf_dirs(configuration, | ||||||
|  |                                            args.conf_dir) | ||||||
|  |         c = cls(conf_dirs, args) | ||||||
|  |         c.run() | ||||||
|  | 
 | ||||||
|  |     def _get_global_explorers(self, conf_path): | ||||||
|  |         rv = [] | ||||||
|  |         global_explorer_path = os.path.join(conf_path, "explorer", | ||||||
|  |                                             self.glob_pattern) | ||||||
|  |         if self.fixed_string: | ||||||
|  |             if os.path.exists(global_explorer_path): | ||||||
|  |                 rv.append(global_explorer_path) | ||||||
|  |         else: | ||||||
|  |             for explorer in glob.glob(global_explorer_path): | ||||||
|  |                 rv.append(explorer) | ||||||
|  |         return rv | ||||||
|  | 
 | ||||||
|  |     def _should_display_type(self, dir_entry): | ||||||
|  |         if not dir_entry.is_dir(): | ||||||
|  |             return False | ||||||
|  |         if self.glob_pattern is None: | ||||||
|  |             return True | ||||||
|  |         if self.fixed_string: | ||||||
|  |             return dir_entry.name == self.glob_pattern | ||||||
|  |         else: | ||||||
|  |             return fnmatch.fnmatch(dir_entry.name, self.glob_pattern) | ||||||
|  | 
 | ||||||
|  |     def _get_types(self, conf_path): | ||||||
|  |         rv = [] | ||||||
|  |         types_path = os.path.join(conf_path, "type") | ||||||
|  |         if not os.path.exists(types_path): | ||||||
|  |             return rv | ||||||
|  |         with os.scandir(types_path) as it: | ||||||
|  |             for entry in it: | ||||||
|  |                 if self._should_display_type(entry): | ||||||
|  |                     rv.append(entry.path) | ||||||
|  |         return rv | ||||||
|  | 
 | ||||||
|  |     def _display_details(self, title, details, default_values=None, | ||||||
|  |                          deprecated=None): | ||||||
|  |         if not details: | ||||||
|  |             return | ||||||
|  |         if isinstance(details, bool): | ||||||
|  |             print("\t{}: {}".format(title, 'yes' if details else 'no')) | ||||||
|  |         elif isinstance(details, str): | ||||||
|  |             print("\t{}: {}".format(title, details)) | ||||||
|  |         elif isinstance(details, list): | ||||||
|  |             dv = dict(default_values) if default_values else {} | ||||||
|  |             dp = dict(deprecated) if deprecated else {} | ||||||
|  | 
 | ||||||
|  |             print("\t{}:".format(title)) | ||||||
|  |             for x in sorted(details): | ||||||
|  |                 print("\t\t{}".format(x), end='') | ||||||
|  |                 has_default = x in dv | ||||||
|  |                 is_deprecated = x in dp | ||||||
|  |                 need_comma = False | ||||||
|  |                 if has_default or is_deprecated: | ||||||
|  |                     print(" (", end='') | ||||||
|  |                 if has_default: | ||||||
|  |                     print("default: {}".format(dv[x]), end='') | ||||||
|  |                     need_comma = True | ||||||
|  |                 if is_deprecated: | ||||||
|  |                     print("{}deprecated".format(', ' if need_comma else ''), | ||||||
|  |                           end='') | ||||||
|  |                 if has_default or is_deprecated: | ||||||
|  |                     print(")", end='') | ||||||
|  |                 print() | ||||||
|  | 
 | ||||||
|  |     def _display_type_parameters(self, cdist_type): | ||||||
|  |         self._display_details("required parameters", | ||||||
|  |                               cdist_type.required_parameters, | ||||||
|  |                               default_values=cdist_type.parameter_defaults, | ||||||
|  |                               deprecated=cdist_type.deprecated_parameters) | ||||||
|  |         self._display_details("required multiple parameters", | ||||||
|  |                               cdist_type.required_multiple_parameters, | ||||||
|  |                               default_values=cdist_type.parameter_defaults, | ||||||
|  |                               deprecated=cdist_type.deprecated_parameters) | ||||||
|  |         self._display_details("optional parameters", | ||||||
|  |                               cdist_type.optional_parameters, | ||||||
|  |                               default_values=cdist_type.parameter_defaults, | ||||||
|  |                               deprecated=cdist_type.deprecated_parameters) | ||||||
|  |         self._display_details("optional multiple parameters", | ||||||
|  |                               cdist_type.optional_multiple_parameters, | ||||||
|  |                               default_values=cdist_type.parameter_defaults, | ||||||
|  |                               deprecated=cdist_type.deprecated_parameters) | ||||||
|  |         self._display_details("boolean parameters", | ||||||
|  |                               cdist_type.boolean_parameters, | ||||||
|  |                               default_values=cdist_type.parameter_defaults, | ||||||
|  |                               deprecated=cdist_type.deprecated_parameters) | ||||||
|  | 
 | ||||||
|  |     def _display_type_characteristics(self, cdist_type): | ||||||
|  |         characteristics = [] | ||||||
|  |         if cdist_type.is_install: | ||||||
|  |             characteristics.append('install') | ||||||
|  |         else: | ||||||
|  |             characteristics.append('config') | ||||||
|  |         if cdist_type.is_singleton: | ||||||
|  |             characteristics.append('singleton') | ||||||
|  |         if cdist_type.is_nonparallel: | ||||||
|  |             characteristics.append('nonparallel') | ||||||
|  |         else: | ||||||
|  |             characteristics.append('parallel') | ||||||
|  |         if cdist_type.deprecated is not None: | ||||||
|  |             characteristics.append('deprecated') | ||||||
|  |         print("\t{}".format(', '.join(characteristics))) | ||||||
|  | 
 | ||||||
|  |     def _display_type_details(self, type_path): | ||||||
|  |         dirname, basename = os.path.split(type_path) | ||||||
|  |         cdist_type = cdist.core.CdistType(dirname, basename) | ||||||
|  | 
 | ||||||
|  |         self._display_type_characteristics(cdist_type) | ||||||
|  |         self._display_type_parameters(cdist_type) | ||||||
|  | 
 | ||||||
|  |     def run(self): | ||||||
|  |         rv = [] | ||||||
|  |         for conf_path in self.conf_dirs: | ||||||
|  |             if self.all or self.display_global_explorers: | ||||||
|  |                 rv.extend((x, 'E', ) for x in self._get_global_explorers( | ||||||
|  |                     conf_path)) | ||||||
|  |             if self.all or self.display_types: | ||||||
|  |                 rv.extend((x, 'T', ) for x in self._get_types(conf_path)) | ||||||
|  |         rv = sorted(rv, key=lambda x: x[0]) | ||||||
|  |         for x, t in rv: | ||||||
|  |             print(x) | ||||||
|  |             if self.full and t == 'T': | ||||||
|  |                 self._display_type_details(x) | ||||||
|  | @ -11,7 +11,7 @@ SYNOPSIS | ||||||
| 
 | 
 | ||||||
| :: | :: | ||||||
| 
 | 
 | ||||||
|     cdist [-h] [-V] {banner,config,install,inventory,preos,shell} ... |     cdist [-h] [-V] {banner,config,install,inventory,preos,shell,info} ... | ||||||
| 
 | 
 | ||||||
|     cdist banner [-h] [-l LOGLEVEL] [-q] [-v] |     cdist banner [-h] [-l LOGLEVEL] [-q] [-v] | ||||||
| 
 | 
 | ||||||
|  | @ -84,6 +84,8 @@ SYNOPSIS | ||||||
| 
 | 
 | ||||||
|     cdist shell [-h] [-l LOGLEVEL] [-q] [-v] [-s SHELL] |     cdist shell [-h] [-l LOGLEVEL] [-q] [-v] [-s SHELL] | ||||||
| 
 | 
 | ||||||
|  |     cdist info [-h] [-a] [-c CONF_DIR] [-e] [-F] [-f] [-t] [pattern] | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| DESCRIPTION | DESCRIPTION | ||||||
| ----------- | ----------- | ||||||
|  | @ -604,6 +606,39 @@ usage. Its primary use is for debugging type parameters. | ||||||
|     be POSIX compatible shell. |     be POSIX compatible shell. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | INFO | ||||||
|  | ---- | ||||||
|  | Display information for cdist (global explorers, types). | ||||||
|  | 
 | ||||||
|  | **pattern** | ||||||
|  |     Glob pattern. If it contains special characters('?', '*', '[') then it is | ||||||
|  |     used as specified, otherwise it is translated to `*pattern*`. | ||||||
|  | 
 | ||||||
|  | **-h, --help** | ||||||
|  |     Show help message and exit. | ||||||
|  | 
 | ||||||
|  | **-a, --all** | ||||||
|  |     Display all info. This is the default. | ||||||
|  | 
 | ||||||
|  | **-c CONF_DIR, --conf-dir CONF_DIR** | ||||||
|  |     Add configuration directory (can be repeated). | ||||||
|  | 
 | ||||||
|  | **-e, --global-explorers** | ||||||
|  |     Display info for global explorers. | ||||||
|  | 
 | ||||||
|  | **-F, --fixed-string** | ||||||
|  |     Interpret pattern as a fixed string. | ||||||
|  | 
 | ||||||
|  | **-f, --full** | ||||||
|  |     Display full details. | ||||||
|  | 
 | ||||||
|  | **-g CONFIG_FILE, --config-file CONFIG_FILE** | ||||||
|  |     Use specified custom configuration file. | ||||||
|  | 
 | ||||||
|  | **-t, --types** | ||||||
|  |     Display info for types. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| CONFIGURATION | CONFIGURATION | ||||||
| ------------- | ------------- | ||||||
| cdist obtains configuration data from the following sources in the following | cdist obtains configuration data from the following sources in the following | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue