from __future__ import absolute_import
+import time
+
from .helper import DashboardTestCase, authenticate
data = self._get('/api/cluster_conf/fantasy_name')
self.assertStatus(404)
+ @authenticate
+ def test_get_specific_db_config_option(self):
+ def _get_mon_allow_pool_delete_config():
+ data = self._get('/api/cluster_conf/mon_allow_pool_delete')
+ return data['value'][0]
+
+ self._ceph_cmd(['config', 'set', 'mon', 'mon_allow_pool_delete', 'true'])
+ result = self._wait_for_expected_get_result(_get_mon_allow_pool_delete_config,
+ {'section': 'mon', 'value': 'true'})
+ self.assertEqual(result, {'section': 'mon', 'value': 'true'})
+
+ self._ceph_cmd(['config', 'set', 'mon', 'mon_allow_pool_delete', 'false'])
+ result = self._wait_for_expected_get_result(_get_mon_allow_pool_delete_config,
+ {'section': 'mon', 'value': 'false'})
+ self.assertEqual(result, {'section': 'mon', 'value': 'false'})
+
def _validate_single(self, data):
self.assertIn('name', data)
self.assertIn('daemon_default', data)
self.assertIn('type', data)
self.assertIn('desc', data)
+ if 'value' in data:
+ self.assertIn('source', data)
+ self.assertIsInstance(data['value'], list)
+
+ for entry in data['value']:
+ self.assertIsInstance(entry, dict)
+ self.assertIn('section', entry)
+ self.assertIn('value', entry)
+
+ def _wait_for_expected_get_result(self, get_func, expected_result, max_attempts=30,
+ sleep_time=1):
+ attempts = 0
+ while attempts < max_attempts:
+ get_result = get_func()
+ if get_result == expected_result:
+ self.assertStatus(200)
+ return get_result
+
+ time.sleep(sleep_time)
+ attempts += 1
import cherrypy
from .. import mgr
+from ..services.ceph_service import CephService
from . import ApiController, RESTController, AuthRequired
@ApiController('/cluster_conf')
@AuthRequired()
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')
+ 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 options
+ return self._append_config_option_values(options)
def get(self, name):
for option in mgr.get('config_options')['options']:
if option['name'] == name:
- return option
+ return self._append_config_option_values([option])[0]
raise cherrypy.HTTPError(404)
</cd-table-key-value>
</tab>
</tabset>
+ <ng-template #confValTpl let-value="value">
+ <span *ngIf="value">
+ <span *ngFor="let conf of value; last as isLast">
+ {{ conf.section }}: {{ conf.value }}{{ !isLast ? "," : "" }}<br/>
+ </span>
+ </span>
+ </ng-template>
</cd-table>
-import { Component } from '@angular/core';
+import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { ConfigurationService } from '../../../shared/api/configuration.service';
import { CdTableColumn } from '../../../shared/models/cd-table-column';
templateUrl: './configuration.component.html',
styleUrls: ['./configuration.component.scss']
})
-export class ConfigurationComponent {
+export class ConfigurationComponent implements OnInit {
data = [];
columns: CdTableColumn[];
selection = new CdTableSelection();
-
filters = [
{
label: 'Level',
return row.services.includes(value);
}
+ },
+ {
+ label: 'Source',
+ prop: 'source',
+ value: 'any',
+ options: ['any', 'mon'],
+ applyFilter: (row, value) => {
+ if (value === 'any') {
+ return true;
+ }
+
+ if (!row.hasOwnProperty('source')) {
+ return false;
+ }
+
+ return row.source.includes(value);
+ }
}
];
- constructor(
- private configurationService: ConfigurationService,
- ) {
+ @ViewChild('confValTpl') public confValTpl: TemplateRef<any>;
+
+ constructor(private configurationService: ConfigurationService) {}
+
+ ngOnInit() {
this.columns = [
{ flexGrow: 2, canAutoResize: true, prop: 'name' },
+ {
+ flexGrow: 2,
+ prop: 'value',
+ name: 'Current value',
+ cellClass: 'wrap',
+ cellTemplate: this.confValTpl
+ },
+ { flexGrow: 1, prop: 'source' },
{ flexGrow: 2, prop: 'desc', name: 'Description', cellClass: 'wrap' },
{ flexGrow: 2, prop: 'long_desc', name: 'Long description', cellClass: 'wrap' },
{ flexGrow: 1, prop: 'type' },
{ flexGrow: 1, prop: 'level' },
- { flexGrow: 1, prop: 'default', cellClass: 'wrap'},
+ { flexGrow: 1, prop: 'default', cellClass: 'wrap' },
{ flexGrow: 2, prop: 'daemon_default', name: 'Daemon default' },
{ flexGrow: 1, prop: 'tags', name: 'Tags' },
{ flexGrow: 1, prop: 'services', name: 'Services' },