summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/controllers/cluster_configuration.py
blob: da5be2cc81d6a5a8a8ec3fa049efe97a49f6a101 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# -*- 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')