Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mgr/dashboard config options add #23230

Merged
merged 10 commits into from
Oct 9, 2018
138 changes: 120 additions & 18 deletions qa/tasks/mgr/dashboard/test_cluster_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,113 @@ def test_get(self):
self.assertStatus(404)

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')
if 'value' in data:
return data['value'][0]
return None
config_name = 'mon_allow_pool_delete'

orig_value = _get_mon_allow_pool_delete_config()
orig_value = self._get_config_by_name(config_name)

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', config_name, 'true'])
result = self._wait_for_expected_get_result(self._get_config_by_name, config_name,
[{'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'})
self._ceph_cmd(['config', 'set', 'mon', config_name, 'false'])
result = self._wait_for_expected_get_result(self._get_config_by_name, config_name,
[{'section': 'mon', 'value': 'false'}])
self.assertEqual(result, [{'section': 'mon', 'value': 'false'}])

# restore value
if orig_value:
self._ceph_cmd(['config', 'set', 'mon', 'mon_allow_pool_delete',
orig_value['value']])
self._ceph_cmd(['config', 'set', 'mon', config_name, orig_value[0]['value']])

def test_create(self):
config_name = 'debug_ms'
orig_value = self._get_config_by_name(config_name)

# remove all existing settings for equal preconditions
self._clear_all_values_for_config_option(config_name)

expected_result = [{'section': 'mon', 'value': '0/3'}]

self._post('/api/cluster_conf', {
'name': config_name,
'value': expected_result
})
self.assertStatus(201)
result = self._wait_for_expected_get_result(self._get_config_by_name, config_name,
expected_result)
self.assertEqual(result, expected_result)

# reset original value
self._clear_all_values_for_config_option(config_name)
self._reset_original_values(config_name, orig_value)

def test_create_two_values(self):
config_name = 'debug_ms'
orig_value = self._get_config_by_name(config_name)

# remove all existing settings for equal preconditions
self._clear_all_values_for_config_option(config_name)

expected_result = [{'section': 'mon', 'value': '0/3'},
{'section': 'osd', 'value': '0/5'}]

self._post('/api/cluster_conf', {
'name': config_name,
'value': expected_result
})
self.assertStatus(201)
result = self._wait_for_expected_get_result(self._get_config_by_name, config_name,
expected_result)
self.assertEqual(result, expected_result)

# reset original value
self._clear_all_values_for_config_option(config_name)
self._reset_original_values(config_name, orig_value)

def test_create_can_handle_none_values(self):
config_name = 'debug_ms'
orig_value = self._get_config_by_name(config_name)

# remove all existing settings for equal preconditions
self._clear_all_values_for_config_option(config_name)

self._post('/api/cluster_conf', {
'name': config_name,
'value': [{'section': 'mon', 'value': '0/3'},
{'section': 'osd', 'value': None}]
})
self.assertStatus(201)

expected_result = [{'section': 'mon', 'value': '0/3'}]
result = self._wait_for_expected_get_result(self._get_config_by_name, config_name,
expected_result)
self.assertEqual(result, expected_result)

# reset original value
self._clear_all_values_for_config_option(config_name)
self._reset_original_values(config_name, orig_value)

def test_create_can_handle_boolean_values(self):
config_name = 'mon_allow_pool_delete'
orig_value = self._get_config_by_name(config_name)

# remove all existing settings for equal preconditions
self._clear_all_values_for_config_option(config_name)

expected_result = [{'section': 'mon', 'value': 'true'}]

self._post('/api/cluster_conf', {
'name': config_name,
'value': [{'section': 'mon', 'value': True}]})
self.assertStatus(201)

result = self._wait_for_expected_get_result(self._get_config_by_name, config_name,
expected_result)
self.assertEqual(result, expected_result)

# reset original value
self._clear_all_values_for_config_option(config_name)
self._reset_original_values(config_name, orig_value)

def _validate_single(self, data):
self.assertIn('name', data)
Expand All @@ -71,14 +156,31 @@ def _validate_single(self, data):
self.assertIn('section', entry)
self.assertIn('value', entry)

def _wait_for_expected_get_result(self, get_func, expected_result, max_attempts=30,
def _wait_for_expected_get_result(self, get_func, get_params, expected_result, max_attempts=30,
sleep_time=1):
attempts = 0
while attempts < max_attempts:
get_result = get_func()
get_result = get_func(get_params)
if get_result == expected_result:
self.assertStatus(200)
return get_result

time.sleep(sleep_time)
attempts += 1

def _get_config_by_name(self, conf_name):
data = self._get('/api/cluster_conf/{}'.format(conf_name))
if 'value' in data:
return data['value']
return None

def _clear_all_values_for_config_option(self, config_name):
values = self._get_config_by_name(config_name)
if values:
for value in values:
self._ceph_cmd(['config', 'rm', value['section'], config_name])

def _reset_original_values(self, config_name, orig_values):
if orig_values:
for value in orig_values:
self._ceph_cmd(['config', 'set', value['section'], config_name, value['value']])
18 changes: 17 additions & 1 deletion src/pybind/mgr/dashboard/controllers/cluster_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

from . import ApiController, RESTController
from .. import mgr
from ..security import Scope
from ..services.ceph_service import CephService


@ApiController('/cluster_conf')
@ApiController('/cluster_conf', Scope.CONFIG_OPT)
class ClusterConfiguration(RESTController):

def _append_config_option_values(self, options):
Expand Down Expand Up @@ -39,3 +40,18 @@ def get(self, name):
return self._append_config_option_values([option])[0]

raise cherrypy.HTTPError(404)

def create(self, name, value):
s0nea marked this conversation as resolved.
Show resolved Hide resolved
availSections = ['global', 'mon', 'mgr', 'osd', 'mds', 'client']

for section in availSections:
for entry in value:
if not entry['value']:
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)
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('Monitors page', () => {
Helper.checkConsole();
});

it('should open and show breadcrumnb', () => {
it('should open and show breadcrumb', () => {
page.navigateTo();
expect(Helper.getBreadcrumbText()).toEqual('Monitors');
});
Expand Down
13 changes: 10 additions & 3 deletions src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { MirroringComponent } from './ceph/block/mirroring/mirroring.component';
import { RbdFormComponent } from './ceph/block/rbd-form/rbd-form.component';
import { RbdImagesComponent } from './ceph/block/rbd-images/rbd-images.component';
import { CephfsListComponent } from './ceph/cephfs/cephfs-list/cephfs-list.component';
import { ConfigurationFormComponent } from './ceph/cluster/configuration/configuration-form/configuration-form.component';
import { ConfigurationComponent } from './ceph/cluster/configuration/configuration.component';
import { HostsComponent } from './ceph/cluster/hosts/hosts.component';
import { MonitorComponent } from './ceph/cluster/monitor/monitor.component';
Expand Down Expand Up @@ -77,9 +78,15 @@ const routes: Routes = [
},
{
path: 'configuration',
component: ConfigurationComponent,
canActivate: [AuthGuardService],
data: { breadcrumbs: 'Cluster/Configuration Documentation' }
data: { breadcrumbs: 'Cluster/Configuration' },
children: [
{ path: '', component: ConfigurationComponent },
{
path: 'edit/:name',
component: ConfigurationFormComponent,
data: { breadcrumbs: 'Edit' }
}
]
},
{
path: 'perf_counters/:type/:id',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { TabsModule } from 'ngx-bootstrap/tabs';

import { SharedModule } from '../../shared/shared.module';
import { PerformanceCounterModule } from '../performance-counter/performance-counter.module';
import { ConfigurationDetailsComponent } from './configuration/configuration-details/configuration-details.component';
import { ConfigurationFormComponent } from './configuration/configuration-form/configuration-form.component';
import { ConfigurationComponent } from './configuration/configuration.component';
import { HostDetailsComponent } from './hosts/host-details/host-details.component';
import { HostsComponent } from './hosts/hosts.component';
Expand Down Expand Up @@ -41,7 +43,9 @@ import { OsdScrubModalComponent } from './osd/osd-scrub-modal/osd-scrub-modal.co
OsdPerformanceHistogramComponent,
OsdScrubModalComponent,
OsdFlagsModalComponent,
HostDetailsComponent
HostDetailsComponent,
ConfigurationDetailsComponent,
ConfigurationFormComponent
]
})
export class ClusterModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<tabset cdTableDetail *ngIf="selection?.hasSingleSelection">
<tab i18n-heading
heading="Details">
<cd-table-key-value [data]="selection.first()" [autoReload]="false">
</cd-table-key-value>
</tab>
</tabset>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { TabsModule } from 'ngx-bootstrap';

import { configureTestBed } from '../../../../../testing/unit-test-helper';
import { DataTableModule } from '../../../../shared/datatable/datatable.module';
import { ConfigurationDetailsComponent } from './configuration-details.component';

describe('ConfigurationDetailsComponent', () => {
let component: ConfigurationDetailsComponent;
let fixture: ComponentFixture<ConfigurationDetailsComponent>;

configureTestBed({
declarations: [ConfigurationDetailsComponent],
imports: [DataTableModule, TabsModule.forRoot()]
});

beforeEach(() => {
fixture = TestBed.createComponent(ConfigurationDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Component, Input, OnChanges } from '@angular/core';

import { CdTableSelection } from '../../../../shared/models/cd-table-selection';

@Component({
selector: 'cd-configuration-details',
templateUrl: './configuration-details.component.html',
styleUrls: ['./configuration-details.component.scss']
})
export class ConfigurationDetailsComponent implements OnChanges {
@Input()
selection: CdTableSelection;
selectedItem: any;

constructor() {}

ngOnChanges() {
if (this.selection.hasSelection) {
this.selectedItem = this.selection.first();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export class ConfigFormCreateRequestModel {
name: string;
value: Array<any> = [];
}
Loading