# -*- coding: utf-8 -*- import cherrypy from .. import mgr from ..exceptions import DashboardException from ..security import Scope from ..services.ceph_service import CephService from . import APIDoc, APIRouter, EndpointDoc, RESTController FILTER_SCHEMA = [{ "name": (str, 'Name of the config option'), "type": (str, 'Config option type'), "level": (str, 'Config option level'), "desc": (str, 'Description of the configuration'), "long_desc": (str, 'Elaborated description'), "default": (str, 'Default value for the config option'), "daemon_default": (str, 'Daemon specific default value'), "tags": ([str], 'Tags associated with the cluster'), "services": ([str], 'Services associated with the config option'), "see_also": ([str], 'Related config options'), "enum_values": ([str], 'List of enums allowed'), "min": (str, 'Minimum value'), "max": (str, 'Maximum value'), "can_update_at_runtime": (bool, 'Check if can update at runtime'), "flags": ([str], 'List of flags associated') }] @APIRouter('/cluster_conf', Scope.CONFIG_OPT) @APIDoc("Manage Cluster Configurations", "ClusterConfiguration") class ClusterConfiguration(RESTController): def _append_config_option_values(self, options): """ Appends values from the config database (if available) to the given options :param options: list of config options :return: list of config options extended by their current values """ config_dump = CephService.send_command('mon', 'config dump') mgr_config = mgr.get('config') config_dump.append({'name': 'fsid', 'section': 'mgr', 'value': mgr_config['fsid']}) for config_dump_entry in config_dump: for i, elem in enumerate(options): if config_dump_entry['name'] == elem['name']: if 'value' not in elem: options[i]['value'] = [] options[i]['source'] = 'mon' options[i]['value'].append({'section': config_dump_entry['section'], 'value': config_dump_entry['value']}) return options def list(self): options = mgr.get('config_options')['options'] return self._append_config_option_values(options) def get(self, name): return self._get_config_option(name) @RESTController.Collection('GET', query_params=['name']) @EndpointDoc("Get Cluster Configuration by name", parameters={ 'names': (str, 'Config option names'), }, responses={200: FILTER_SCHEMA}) def filter(self, names=None): config_options = [] if names: for name in names.split(','): try: config_options.append(self._get_config_option(name)) except cherrypy.HTTPError: pass if not config_options: raise cherrypy.HTTPError(404, 'Config options `{}` not found'.format(names)) return config_options def create(self, name, value): # Check if config option is updateable at runtime self._updateable_at_runtime([name]) # Update config option avail_sections = ['global', 'mon', 'mgr', 'osd', 'mds', 'client'] for section in avail_sections: for entry in value: if entry['value'] is None: break if entry['section'] == section: CephService.send_command('mon', 'config set', who=section, name=name, value=str(entry['value'])) break else: CephService.send_command('mon', 'config rm', who=section, name=name) def delete(self, name, section): return CephService.send_command('mon', 'config rm', who=section, name=name) def bulk_set(self, options): self._updateable_at_runtime(options.keys()) for name, value in options.items(): CephService.send_command('mon', 'config set', who=value['section'], name=name, value=str(value['value'])) def _get_config_option(self, name): for option in mgr.get('config_options')['options']: if option['name'] == name: return self._append_config_option_values([option])[0] raise cherrypy.HTTPError(404) def _updateable_at_runtime(self, config_option_names): not_updateable = [] for name in config_option_names: config_option = self._get_config_option(name) if not config_option['can_update_at_runtime']: not_updateable.append(name) if not_updateable: raise DashboardException( msg='Config option {} is/are not updatable at runtime'.format( ', '.join(not_updateable)), code='config_option_not_updatable_at_runtime', component='cluster_configuration')