]>
git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/mgr/dashboard/test_cluster_configuration.py
61d18000a45a4078a389d9213d4c59ccdb7f5c96
1 from __future__
import absolute_import
5 from .helper
import DashboardTestCase
8 class ClusterConfigurationTest(DashboardTestCase
):
11 data
= self
._get
('/api/cluster_conf')
12 self
.assertStatus(200)
13 self
.assertIsInstance(data
, list)
14 self
.assertGreater(len(data
), 1000)
16 self
._validate
_single
(conf
)
19 data
= self
._get
('/api/cluster_conf/admin_socket')
20 self
.assertStatus(200)
21 self
._validate
_single
(data
)
22 self
.assertIn('enum_values', data
)
24 data
= self
._get
('/api/cluster_conf/fantasy_name')
25 self
.assertStatus(404)
27 def test_get_specific_db_config_option(self
):
28 config_name
= 'mon_allow_pool_delete'
30 orig_value
= self
._get
_config
_by
_name
(config_name
)
32 self
._ceph
_cmd
(['config', 'set', 'mon', config_name
, 'true'])
33 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
34 [{'section': 'mon', 'value': 'true'}])
35 self
.assertEqual(result
, [{'section': 'mon', 'value': 'true'}])
37 self
._ceph
_cmd
(['config', 'set', 'mon', config_name
, 'false'])
38 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
39 [{'section': 'mon', 'value': 'false'}])
40 self
.assertEqual(result
, [{'section': 'mon', 'value': 'false'}])
44 self
._ceph
_cmd
(['config', 'set', 'mon', config_name
, orig_value
[0]['value']])
46 def test_filter_config_options(self
):
47 config_names
= ['osd_scrub_during_recovery', 'osd_scrub_begin_hour', 'osd_scrub_end_hour']
48 data
= self
._get
('/api/cluster_conf/filter?names={}'.format(','.join(config_names
)))
49 self
.assertStatus(200)
50 self
.assertIsInstance(data
, list)
51 self
.assertEqual(len(data
), 3)
53 self
._validate
_single
(conf
)
54 self
.assertIn(conf
['name'], config_names
)
56 def test_filter_config_options_empty_names(self
):
57 self
._get
('/api/cluster_conf/filter?names=')
58 self
.assertStatus(404)
59 self
.assertEqual(self
._resp
.json()['detail'], 'Config options `` not found')
61 def test_filter_config_options_unknown_name(self
):
62 self
._get
('/api/cluster_conf/filter?names=abc')
63 self
.assertStatus(404)
64 self
.assertEqual(self
._resp
.json()['detail'], 'Config options `abc` not found')
66 def test_filter_config_options_contains_unknown_name(self
):
67 config_names
= ['osd_scrub_during_recovery', 'osd_scrub_begin_hour', 'abc']
68 data
= self
._get
('/api/cluster_conf/filter?names={}'.format(','.join(config_names
)))
69 self
.assertStatus(200)
70 self
.assertIsInstance(data
, list)
71 self
.assertEqual(len(data
), 2)
73 self
._validate
_single
(conf
)
74 self
.assertIn(conf
['name'], config_names
)
76 def test_create(self
):
77 config_name
= 'debug_ms'
78 orig_value
= self
._get
_config
_by
_name
(config_name
)
80 # remove all existing settings for equal preconditions
81 self
._clear
_all
_values
_for
_config
_option
(config_name
)
83 expected_result
= [{'section': 'mon', 'value': '0/3'}]
85 self
._post
('/api/cluster_conf', {
87 'value': expected_result
89 self
.assertStatus(201)
90 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
92 self
.assertEqual(result
, expected_result
)
94 # reset original value
95 self
._clear
_all
_values
_for
_config
_option
(config_name
)
96 self
._reset
_original
_values
(config_name
, orig_value
)
98 def test_delete(self
):
99 config_name
= 'debug_ms'
100 orig_value
= self
._get
_config
_by
_name
(config_name
)
102 # set a config option
103 expected_result
= [{'section': 'mon', 'value': '0/3'}]
104 self
._post
('/api/cluster_conf', {
106 'value': expected_result
108 self
.assertStatus(201)
109 self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
, expected_result
)
111 # delete it and check if it's deleted
112 self
._delete
('/api/cluster_conf/{}?section={}'.format(config_name
, 'mon'))
113 self
.assertStatus(204)
114 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
, None)
115 self
.assertEqual(result
, None)
117 # reset original value
118 self
._clear
_all
_values
_for
_config
_option
(config_name
)
119 self
._reset
_original
_values
(config_name
, orig_value
)
121 def test_create_cant_update_at_runtime(self
):
122 config_name
= 'public_bind_addr' # not updatable
123 config_value
= [{'section': 'global', 'value': 'true'}]
124 orig_value
= self
._get
_config
_by
_name
(config_name
)
126 # try to set config option and check if it fails
127 self
._post
('/api/cluster_conf', {
129 'value': config_value
131 self
.assertStatus(400)
132 self
.assertError(code
='config_option_not_updatable_at_runtime',
133 component
='cluster_configuration',
134 detail
='Config option {} is/are not updatable at runtime'.format(
137 # check if config option value is still the original one
138 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
140 self
.assertEqual(result
, orig_value
)
142 def test_create_two_values(self
):
143 config_name
= 'debug_ms'
144 orig_value
= self
._get
_config
_by
_name
(config_name
)
146 # remove all existing settings for equal preconditions
147 self
._clear
_all
_values
_for
_config
_option
(config_name
)
149 expected_result
= [{'section': 'mon', 'value': '0/3'},
150 {'section': 'osd', 'value': '0/5'}]
152 self
._post
('/api/cluster_conf', {
154 'value': expected_result
156 self
.assertStatus(201)
157 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
159 self
.assertEqual(result
, expected_result
)
161 # reset original value
162 self
._clear
_all
_values
_for
_config
_option
(config_name
)
163 self
._reset
_original
_values
(config_name
, orig_value
)
165 def test_create_can_handle_none_values(self
):
166 config_name
= 'debug_ms'
167 orig_value
= self
._get
_config
_by
_name
(config_name
)
169 # remove all existing settings for equal preconditions
170 self
._clear
_all
_values
_for
_config
_option
(config_name
)
172 self
._post
('/api/cluster_conf', {
174 'value': [{'section': 'mon', 'value': '0/3'},
175 {'section': 'osd', 'value': None}]
177 self
.assertStatus(201)
179 expected_result
= [{'section': 'mon', 'value': '0/3'}]
180 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
182 self
.assertEqual(result
, expected_result
)
184 # reset original value
185 self
._clear
_all
_values
_for
_config
_option
(config_name
)
186 self
._reset
_original
_values
(config_name
, orig_value
)
188 def test_create_can_handle_boolean_values(self
):
189 config_name
= 'mon_allow_pool_delete'
190 orig_value
= self
._get
_config
_by
_name
(config_name
)
192 # remove all existing settings for equal preconditions
193 self
._clear
_all
_values
_for
_config
_option
(config_name
)
195 expected_result
= [{'section': 'mon', 'value': 'true'}]
197 self
._post
('/api/cluster_conf', {
199 'value': [{'section': 'mon', 'value': True}]})
200 self
.assertStatus(201)
202 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
204 self
.assertEqual(result
, expected_result
)
206 # reset original value
207 self
._clear
_all
_values
_for
_config
_option
(config_name
)
208 self
._reset
_original
_values
(config_name
, orig_value
)
210 def test_bulk_set(self
):
212 'osd_max_backfills': {'section': 'osd', 'value': '1'},
213 'osd_recovery_max_active': {'section': 'osd', 'value': '3'},
214 'osd_recovery_max_single_start': {'section': 'osd', 'value': '1'},
215 'osd_recovery_sleep': {'section': 'osd', 'value': '2.000000'}
219 for config_name
in expected_result
:
220 orig_values
[config_name
] = self
._get
_config
_by
_name
(config_name
)
222 # remove all existing settings for equal preconditions
223 self
._clear
_all
_values
_for
_config
_option
(config_name
)
225 self
._put
('/api/cluster_conf', {'options': expected_result
})
226 self
.assertStatus(200)
228 for config_name
, value
in expected_result
.items():
229 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
231 self
.assertEqual(result
, [value
])
233 # reset original value
234 self
._clear
_all
_values
_for
_config
_option
(config_name
)
235 self
._reset
_original
_values
(config_name
, orig_values
[config_name
])
237 def test_bulk_set_cant_update_at_runtime(self
):
239 'public_bind_addr': {'section': 'global', 'value': '1.2.3.4:567'}, # not updatable
240 'public_network': {'section': 'global', 'value': '10.0.0.0/8'} # not updatable
244 for config_name
in config_options
:
245 orig_values
[config_name
] = self
._get
_config
_by
_name
(config_name
)
247 # try to set config options and see if it fails
248 self
._put
('/api/cluster_conf', {'options': config_options
})
249 self
.assertStatus(400)
250 self
.assertError(code
='config_option_not_updatable_at_runtime',
251 component
='cluster_configuration',
252 detail
='Config option {} is/are not updatable at runtime'.format(
253 ', '.join(config_options
.keys())))
255 # check if config option values are still the original ones
256 for config_name
, value
in orig_values
.items():
257 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
259 self
.assertEqual(result
, value
)
261 def test_bulk_set_cant_update_at_runtime_partial(self
):
263 'public_bind_addr': {'section': 'global', 'value': 'true'}, # not updatable
264 'log_to_stderr': {'section': 'global', 'value': 'true'} # updatable
268 for config_name
in config_options
:
269 orig_values
[config_name
] = self
._get
_config
_by
_name
(config_name
)
271 # try to set config options and see if it fails
272 self
._put
('/api/cluster_conf', {'options': config_options
})
273 self
.assertStatus(400)
274 self
.assertError(code
='config_option_not_updatable_at_runtime',
275 component
='cluster_configuration',
276 detail
='Config option {} is/are not updatable at runtime'.format(
279 # check if config option values are still the original ones
280 for config_name
, value
in orig_values
.items():
281 result
= self
._wait
_for
_expected
_get
_result
(self
._get
_config
_by
_name
, config_name
,
283 self
.assertEqual(result
, value
)
285 def test_check_existence(self
):
287 This test case is intended to check the existence of all hard coded config options used by
289 If you include further hard coded options in the dashboard, feel free to add them to the
292 hard_coded_options
= [
293 'osd_max_backfills', # osd-recv-speed
294 'osd_recovery_max_active', # osd-recv-speed
295 'osd_recovery_max_single_start', # osd-recv-speed
296 'osd_recovery_sleep', # osd-recv-speed
297 'osd_scrub_during_recovery', # osd-pg-scrub
298 'osd_scrub_begin_hour', # osd-pg-scrub
299 'osd_scrub_end_hour', # osd-pg-scrub
300 'osd_scrub_begin_week_day', # osd-pg-scrub
301 'osd_scrub_end_week_day', # osd-pg-scrub
302 'osd_scrub_min_interval', # osd-pg-scrub
303 'osd_scrub_max_interval', # osd-pg-scrub
304 'osd_deep_scrub_interval', # osd-pg-scrub
305 'osd_scrub_auto_repair', # osd-pg-scrub
306 'osd_max_scrubs', # osd-pg-scrub
307 'osd_scrub_priority', # osd-pg-scrub
308 'osd_scrub_sleep', # osd-pg-scrub
309 'osd_scrub_auto_repair_num_errors', # osd-pg-scrub
310 'osd_debug_deep_scrub_sleep', # osd-pg-scrub
311 'osd_deep_scrub_keys', # osd-pg-scrub
312 'osd_deep_scrub_large_omap_object_key_threshold', # osd-pg-scrub
313 'osd_deep_scrub_large_omap_object_value_sum_threshold', # osd-pg-scrub
314 'osd_deep_scrub_randomize_ratio', # osd-pg-scrub
315 'osd_deep_scrub_stride', # osd-pg-scrub
316 'osd_deep_scrub_update_digest_min_age', # osd-pg-scrub
317 'osd_requested_scrub_priority', # osd-pg-scrub
318 'osd_scrub_backoff_ratio', # osd-pg-scrub
319 'osd_scrub_chunk_max', # osd-pg-scrub
320 'osd_scrub_chunk_min', # osd-pg-scrub
321 'osd_scrub_cost', # osd-pg-scrub
322 'osd_scrub_interval_randomize_ratio', # osd-pg-scrub
323 'osd_scrub_invalid_stats', # osd-pg-scrub
324 'osd_scrub_load_threshold', # osd-pg-scrub
325 'osd_scrub_max_preemptions', # osd-pg-scrub
326 'mon_allow_pool_delete' # pool-list
329 for config_option
in hard_coded_options
:
330 self
._get
('/api/cluster_conf/{}'.format(config_option
))
331 self
.assertStatus(200)
333 def _validate_single(self
, data
):
334 self
.assertIn('name', data
)
335 self
.assertIn('daemon_default', data
)
336 self
.assertIn('long_desc', data
)
337 self
.assertIn('level', data
)
338 self
.assertIn('default', data
)
339 self
.assertIn('see_also', data
)
340 self
.assertIn('tags', data
)
341 self
.assertIn('min', data
)
342 self
.assertIn('max', data
)
343 self
.assertIn('services', data
)
344 self
.assertIn('type', data
)
345 self
.assertIn('desc', data
)
346 self
.assertIn(data
['type'], ['str', 'bool', 'float', 'int', 'size', 'uint', 'addr', 'addrvec', 'uuid',
350 self
.assertIn('source', data
)
351 self
.assertIsInstance(data
['value'], list)
353 for entry
in data
['value']:
354 self
.assertIsInstance(entry
, dict)
355 self
.assertIn('section', entry
)
356 self
.assertIn('value', entry
)
358 def _wait_for_expected_get_result(self
, get_func
, get_params
, expected_result
, max_attempts
=30,
361 while attempts
< max_attempts
:
362 get_result
= get_func(get_params
)
363 if get_result
== expected_result
:
364 self
.assertStatus(200)
367 time
.sleep(sleep_time
)
370 def _get_config_by_name(self
, conf_name
):
371 data
= self
._get
('/api/cluster_conf/{}'.format(conf_name
))
376 def _clear_all_values_for_config_option(self
, config_name
):
377 values
= self
._get
_config
_by
_name
(config_name
)
380 self
._ceph
_cmd
(['config', 'rm', value
['section'], config_name
])
382 def _reset_original_values(self
, config_name
, orig_values
):
384 for value
in orig_values
:
385 self
._ceph
_cmd
(['config', 'set', value
['section'], config_name
, value
['value']])