]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/plugins/feature_toggles.py
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / pybind / mgr / dashboard / plugins / feature_toggles.py
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import
3
4 from enum import Enum
5 import cherrypy
6 from mgr_module import CLICommand, Option
7
8 from . import PLUGIN_MANAGER as PM
9 from . import interfaces as I
10 from .ttl_cache import ttl_cache
11
12 from ..controllers.rbd import Rbd, RbdSnapshot, RbdTrash
13 from ..controllers.rbd_mirroring import (
14 RbdMirroringSummary, RbdMirroringPoolMode, RbdMirroringPoolPeer)
15 from ..controllers.iscsi import Iscsi, IscsiTarget
16 from ..controllers.cephfs import CephFS
17 from ..controllers.rgw import Rgw, RgwDaemon, RgwBucket, RgwUser
18
19
20 class Features(Enum):
21 RBD = 'rbd'
22 MIRRORING = 'mirroring'
23 ISCSI = 'iscsi'
24 CEPHFS = 'cephfs'
25 RGW = 'rgw'
26
27
28 PREDISABLED_FEATURES = set()
29
30
31 Feature2Controller = {
32 Features.RBD: [Rbd, RbdSnapshot, RbdTrash],
33 Features.MIRRORING: [
34 RbdMirroringSummary, RbdMirroringPoolMode, RbdMirroringPoolPeer],
35 Features.ISCSI: [Iscsi, IscsiTarget],
36 Features.CEPHFS: [CephFS],
37 Features.RGW: [Rgw, RgwDaemon, RgwBucket, RgwUser],
38 }
39
40
41 class Actions(Enum):
42 ENABLE = 'enable'
43 DISABLE = 'disable'
44 STATUS = 'status'
45
46
47 @PM.add_plugin
48 class FeatureToggles(I.CanMgr, I.CanLog, I.Setupable, I.HasOptions,
49 I.HasCommands, I.FilterRequest.BeforeHandler,
50 I.HasControllers):
51 OPTION_FMT = 'FEATURE_TOGGLE_{}'
52 CACHE_MAX_SIZE = 128 # Optimum performance with 2^N sizes
53 CACHE_TTL = 10 # seconds
54
55 @PM.add_hook
56 def setup(self):
57 self.Controller2Feature = {
58 controller: feature
59 for feature, controllers in Feature2Controller.items()
60 for controller in controllers}
61
62 @PM.add_hook
63 def get_options(self):
64 return [Option(
65 name=self.OPTION_FMT.format(feature.value),
66 default=(feature not in PREDISABLED_FEATURES),
67 type='bool',) for feature in Features]
68
69 @PM.add_hook
70 def register_commands(self):
71 @CLICommand(
72 "dashboard feature",
73 "name=action,type=CephChoices,strings={} ".format(
74 "|".join(a.value for a in Actions))
75 + "name=features,type=CephChoices,strings={},req=false,n=N".format(
76 "|".join(f.value for f in Features)),
77 "Enable or disable features in Ceph-Mgr Dashboard")
78 def cmd(mgr, action, features=None):
79 ret = 0
80 msg = []
81 if action in [Actions.ENABLE.value, Actions.DISABLE.value]:
82 if features is None:
83 ret = 1
84 msg = ["At least one feature must be specified"]
85 else:
86 for feature in features:
87 mgr.set_module_option(
88 self.OPTION_FMT.format(feature),
89 action == Actions.ENABLE.value)
90 msg += ["Feature '{}': {}".format(
91 feature,
92 'enabled' if action == Actions.ENABLE.value else
93 'disabled')]
94 else:
95 for feature in features or [f.value for f in Features]:
96 enabled = mgr.get_module_option(self.OPTION_FMT.format(feature))
97 msg += ["Feature '{}': '{}'".format(
98 feature,
99 'enabled' if enabled else 'disabled')]
100 return ret, '\n'.join(msg), ''
101 return {'handle_command': cmd}
102
103 def _get_feature_from_request(self, request):
104 try:
105 return self.Controller2Feature[
106 request.handler.callable.__self__]
107 except (AttributeError, KeyError):
108 return None
109
110 @ttl_cache(ttl=CACHE_TTL, maxsize=CACHE_MAX_SIZE)
111 def _is_feature_enabled(self, feature):
112 return self.mgr.get_module_option(self.OPTION_FMT.format(feature.value))
113
114 @PM.add_hook
115 def filter_request_before_handler(self, request):
116 feature = self._get_feature_from_request(request)
117 if feature is None:
118 return
119
120 if not self._is_feature_enabled(feature):
121 raise cherrypy.HTTPError(
122 404, "Feature='{}' disabled by option '{}'".format(
123 feature.value,
124 self.OPTION_FMT.format(feature.value),
125 )
126 )
127
128 @PM.add_hook
129 def get_controllers(self):
130 from ..controllers import ApiController, RESTController
131
132 @ApiController('/feature_toggles')
133 class FeatureTogglesEndpoint(RESTController):
134
135 def list(_):
136 return {
137 feature.value: self._is_feature_enabled(feature)
138 for feature in Features
139 }
140 return [FeatureTogglesEndpoint]