# -*- coding: utf-8 -*- from __future__ import absolute_import import errno import inspect from six import add_metaclass from mgr_module import CLICheckNonemptyFileInput from . import mgr class Options(object): """ If you need to store some configuration value please add the config option name as a class attribute to this class. Example:: GRAFANA_API_HOST = ('localhost', str) GRAFANA_API_PORT = (3000, int) """ ENABLE_BROWSABLE_API = (True, bool) REST_REQUESTS_TIMEOUT = (45, int) # API auditing AUDIT_API_ENABLED = (False, bool) AUDIT_API_LOG_PAYLOAD = (True, bool) # RGW settings RGW_API_HOST = ('', str) RGW_API_PORT = (80, int) RGW_API_ACCESS_KEY = ('', str) RGW_API_SECRET_KEY = ('', str) RGW_API_ADMIN_RESOURCE = ('admin', str) RGW_API_SCHEME = ('http', str) RGW_API_USER_ID = ('', str) RGW_API_SSL_VERIFY = (True, bool) # Grafana settings GRAFANA_API_URL = ('', str) GRAFANA_FRONTEND_API_URL = ('', str) GRAFANA_API_USERNAME = ('admin', str) GRAFANA_API_PASSWORD = ('admin', str) GRAFANA_API_SSL_VERIFY = (True, bool) GRAFANA_UPDATE_DASHBOARDS = (False, bool) # NFS Ganesha settings GANESHA_CLUSTERS_RADOS_POOL_NAMESPACE = ('', str) # Prometheus settings PROMETHEUS_API_HOST = ('', str) ALERTMANAGER_API_HOST = ('', str) # iSCSI management settings ISCSI_API_SSL_VERIFICATION = (True, bool) @staticmethod def has_default_value(name): return getattr(Settings, name, None) is None or \ getattr(Settings, name) == getattr(Options, name)[0] class SettingsMeta(type): def __getattr__(cls, attr): default, stype = getattr(Options, attr) if stype == bool and str(mgr.get_module_option( attr, default)).lower() == 'false': value = False else: value = stype(mgr.get_module_option(attr, default)) return value def __setattr__(cls, attr, value): if not attr.startswith('_') and hasattr(Options, attr): mgr.set_module_option(attr, str(value)) else: setattr(SettingsMeta, attr, value) def __delattr__(cls, attr): if not attr.startswith('_') and hasattr(Options, attr): mgr.set_module_option(attr, None) # pylint: disable=no-init @add_metaclass(SettingsMeta) class Settings(object): pass def _options_command_map(): def filter_attr(member): return not inspect.isroutine(member) cmd_map = {} for option, value in inspect.getmembers(Options, filter_attr): if option.startswith('_'): continue key_get = 'dashboard get-{}'.format(option.lower().replace('_', '-')) key_set = 'dashboard set-{}'.format(option.lower().replace('_', '-')) key_reset = 'dashboard reset-{}'.format(option.lower().replace('_', '-')) cmd_map[key_get] = {'name': option, 'type': None} cmd_map[key_set] = {'name': option, 'type': value[1]} cmd_map[key_reset] = {'name': option, 'type': None} return cmd_map _OPTIONS_COMMAND_MAP = _options_command_map() def options_command_list(): """ This function generates a list of ``get`` and ``set`` commands for each declared configuration option in class ``Options``. """ def py2ceph(pytype): if pytype == str: return 'CephString' elif pytype == int: return 'CephInt' return 'CephString' cmd_list = [] for cmd, opt in _OPTIONS_COMMAND_MAP.items(): if cmd.startswith('dashboard get'): cmd_list.append({ 'cmd': '{}'.format(cmd), 'desc': 'Get the {} option value'.format(opt['name']), 'perm': 'r' }) elif cmd.startswith('dashboard set'): cmd_entry = { 'cmd': '{} name=value,type={}' .format(cmd, py2ceph(opt['type'])), 'desc': 'Set the {} option value'.format(opt['name']), 'perm': 'w' } if handles_secret(cmd): cmd_entry['cmd'] = cmd cmd_entry['desc'] = '{} read from -i '.format(cmd_entry['desc']) cmd_list.append(cmd_entry) elif cmd.startswith('dashboard reset'): desc = 'Reset the {} option to its default value'.format( opt['name']) cmd_list.append({ 'cmd': '{}'.format(cmd), 'desc': desc, 'perm': 'w' }) return cmd_list def options_schema_list(): def filter_attr(member): return not inspect.isroutine(member) result = [] for option, value in inspect.getmembers(Options, filter_attr): if option.startswith('_'): continue result.append({'name': option, 'default': value[0], 'type': value[1].__name__}) return result def handle_option_command(cmd, inbuf): if cmd['prefix'] not in _OPTIONS_COMMAND_MAP: return -errno.ENOSYS, '', "Command not found '{}'".format(cmd['prefix']) opt = _OPTIONS_COMMAND_MAP[cmd['prefix']] if cmd['prefix'].startswith('dashboard reset'): delattr(Settings, opt['name']) return 0, 'Option {} reset to default value "{}"'.format( opt['name'], getattr(Settings, opt['name'])), '' elif cmd['prefix'].startswith('dashboard get'): return 0, str(getattr(Settings, opt['name'])), '' elif cmd['prefix'].startswith('dashboard set'): if handles_secret(cmd['prefix']): value, stdout, stderr = get_secret(inbuf=inbuf) if stderr: return value, stdout, stderr else: value = cmd['value'] value = opt['type'](value) if opt['type'] == bool and cmd['value'].lower() == 'false': value = False setattr(Settings, opt['name'], value) return 0, 'Option {} updated'.format(opt['name']), '' def handles_secret(cmd): return bool([cmd for secret_word in ['password', 'key'] if (secret_word in cmd)]) @CLICheckNonemptyFileInput def get_secret(inbuf=None): return inbuf, None, None