forked from ungleich-public/cdist
Merge branch 'feature/info-command' into 'master'
Add cdist info command See merge request ungleich-public/cdist!825
This commit is contained in:
commit
9b2e273bd1
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…
Reference in a new issue