]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/plugins/feature_toggles.py
c71d325476774f28f1d64db80208159d8aa229b8
1 # -*- coding: utf-8 -*-
4 from typing
import List
, Optional
, Set
, no_type_check
7 from mgr_module
import CLICommand
, Option
9 from ..controllers
.cephfs
import CephFS
10 from ..controllers
.iscsi
import Iscsi
, IscsiTarget
11 from ..controllers
.nfs
import NFSGanesha
, NFSGaneshaExports
12 from ..controllers
.rbd
import Rbd
, RbdSnapshot
, RbdTrash
13 from ..controllers
.rbd_mirroring
import RbdMirroringPoolMode
, \
14 RbdMirroringPoolPeer
, RbdMirroringSummary
15 from ..controllers
.rgw
import Rgw
, RgwBucket
, RgwDaemon
, RgwUser
16 from . import PLUGIN_MANAGER
as PM
17 from . import interfaces
as I
# noqa: E741,N812
18 from .ttl_cache
import ttl_cache
23 MIRRORING
= 'mirroring'
30 PREDISABLED_FEATURES
= set() # type: Set[str]
32 Feature2Controller
= {
33 Features
.RBD
: [Rbd
, RbdSnapshot
, RbdTrash
],
35 RbdMirroringSummary
, RbdMirroringPoolMode
, RbdMirroringPoolPeer
],
36 Features
.ISCSI
: [Iscsi
, IscsiTarget
],
37 Features
.CEPHFS
: [CephFS
],
38 Features
.RGW
: [Rgw
, RgwDaemon
, RgwBucket
, RgwUser
],
39 Features
.NFS
: [NFSGanesha
, NFSGaneshaExports
],
49 # pylint: disable=too-many-ancestors
51 class FeatureToggles(I
.CanMgr
, I
.Setupable
, I
.HasOptions
,
52 I
.HasCommands
, I
.FilterRequest
.BeforeHandler
,
54 OPTION_FMT
= 'FEATURE_TOGGLE_{.name}'
55 CACHE_MAX_SIZE
= 128 # Optimum performance with 2^N sizes
56 CACHE_TTL
= 10 # seconds
60 # pylint: disable=attribute-defined-outside-init
61 self
.Controller2Feature
= {
63 for feature
, controllers
in Feature2Controller
.items()
64 for controller
in controllers
} # type: ignore
67 def get_options(self
):
69 name
=self
.OPTION_FMT
.format(feature
),
70 default
=(feature
not in PREDISABLED_FEATURES
),
71 type='bool',) for feature
in Features
]
74 def register_commands(self
):
75 @CLICommand("dashboard feature")
77 action
: Actions
= Actions
.STATUS
,
78 features
: Optional
[List
[Features
]] = None):
80 Enable or disable features in Ceph-Mgr Dashboard
84 if action
in [Actions
.ENABLE
, Actions
.DISABLE
]:
87 msg
= ["At least one feature must be specified"]
89 for feature
in features
:
90 mgr
.set_module_option(
91 self
.OPTION_FMT
.format(feature
),
92 action
== Actions
.ENABLE
)
93 msg
+= ["Feature '{.value}': {}".format(
95 'enabled' if action
== Actions
.ENABLE
else
98 for feature
in features
or list(Features
):
99 enabled
= mgr
.get_module_option(self
.OPTION_FMT
.format(feature
))
100 msg
+= ["Feature '{.value}': {}".format(
102 'enabled' if enabled
else 'disabled')]
103 return ret
, '\n'.join(msg
), ''
104 return {'handle_command': cmd
}
106 @no_type_check # https://github.com/python/mypy/issues/7806
107 def _get_feature_from_request(self
, request
):
109 return self
.Controller2Feature
[
110 request
.handler
.callable.__self
__]
111 except (AttributeError, KeyError):
114 @ttl_cache(ttl
=CACHE_TTL
, maxsize
=CACHE_MAX_SIZE
)
115 @no_type_check # https://github.com/python/mypy/issues/7806
116 def _is_feature_enabled(self
, feature
):
117 return self
.mgr
.get_module_option(self
.OPTION_FMT
.format(feature
))
120 def filter_request_before_handler(self
, request
):
121 feature
= self
._get
_feature
_from
_request
(request
)
125 if not self
._is
_feature
_enabled
(feature
):
126 raise cherrypy
.HTTPError(
127 404, "Feature='{}' disabled by option '{}'".format(
129 self
.OPTION_FMT
.format(feature
),
134 def get_controllers(self
):
135 from ..controllers
import APIDoc
, APIRouter
, EndpointDoc
, RESTController
139 "mirroring": (bool, ''),
141 "cephfs": (bool, ''),
146 @APIRouter('/feature_toggles')
147 @APIDoc("Manage Features API", "FeatureTogglesEndpoint")
148 class FeatureTogglesEndpoint(RESTController
):
149 @EndpointDoc("Get List Of Features",
150 responses
={200: FEATURES_SCHEMA
})
151 def list(_
): # pylint: disable=no-self-argument # noqa: N805
153 # pylint: disable=protected-access
154 feature
.value
: self
._is
_feature
_enabled
(feature
)
155 for feature
in Features
157 return [FeatureTogglesEndpoint
]