X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ceph%2Fsrc%2Fpybind%2Fmgr%2Fdashboard%2Ffrontend%2Fsrc%2Fapp%2Fceph%2Fcluster%2Ftelemetry%2Ftelemetry.component.ts;h=882a2fe3c403637aafe50ca0d9faf4a7ca481846;hb=20effc670b57271cb089376d6d0800990e5218d5;hp=d6d928e19500c8f15bf53ef347c6df454b360254;hpb=f6b5b4d738b87d88d2de35127b6b0e41eae2a272;p=ceph.git diff --git a/ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/telemetry/telemetry.component.ts b/ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/telemetry/telemetry.component.ts index d6d928e19..882a2fe3c 100644 --- a/ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/telemetry/telemetry.component.ts +++ b/ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/telemetry/telemetry.component.ts @@ -2,66 +2,65 @@ import { Component, OnInit } from '@angular/core'; import { ValidatorFn, Validators } from '@angular/forms'; import { Router } from '@angular/router'; -import { I18n } from '@ngx-translate/i18n-polyfill'; -import * as _ from 'lodash'; -import { BlockUI, NgBlockUI } from 'ng-block-ui'; +import _ from 'lodash'; import { forkJoin as observableForkJoin } from 'rxjs'; -import { MgrModuleService } from '../../../shared/api/mgr-module.service'; -import { TelemetryService } from '../../../shared/api/telemetry.service'; -import { NotificationType } from '../../../shared/enum/notification-type.enum'; -import { CdFormBuilder } from '../../../shared/forms/cd-form-builder'; -import { CdFormGroup } from '../../../shared/forms/cd-form-group'; -import { CdValidators } from '../../../shared/forms/cd-validators'; -import { NotificationService } from '../../../shared/services/notification.service'; -import { TelemetryNotificationService } from '../../../shared/services/telemetry-notification.service'; -import { TextToDownloadService } from '../../../shared/services/text-to-download.service'; +import { MgrModuleService } from '~/app/shared/api/mgr-module.service'; +import { TelemetryService } from '~/app/shared/api/telemetry.service'; +import { ActionLabelsI18n } from '~/app/shared/constants/app.constants'; +import { NotificationType } from '~/app/shared/enum/notification-type.enum'; +import { CdForm } from '~/app/shared/forms/cd-form'; +import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder'; +import { CdFormGroup } from '~/app/shared/forms/cd-form-group'; +import { NotificationService } from '~/app/shared/services/notification.service'; +import { TelemetryNotificationService } from '~/app/shared/services/telemetry-notification.service'; @Component({ selector: 'cd-telemetry', templateUrl: './telemetry.component.html', styleUrls: ['./telemetry.component.scss'] }) -export class TelemetryComponent implements OnInit { - @BlockUI() - blockUI: NgBlockUI; - - error = false; +export class TelemetryComponent extends CdForm implements OnInit { configForm: CdFormGroup; licenseAgrmt = false; - loading = false; moduleEnabled: boolean; options: Object = {}; + newConfig: Object = {}; + configResp: object = {}; previewForm: CdFormGroup; requiredFields = [ 'channel_basic', 'channel_crash', 'channel_device', 'channel_ident', + 'channel_perf', 'interval', 'proxy', 'contact', - 'description' + 'description', + 'organization' ]; + contactInfofields = ['contact', 'description', 'organization']; report: object = undefined; reportId: number = undefined; sendToUrl = ''; sendToDeviceUrl = ''; step = 1; + showContactInfo: boolean; constructor( + public actionLabels: ActionLabelsI18n, private formBuilder: CdFormBuilder, private mgrModuleService: MgrModuleService, private notificationService: NotificationService, private router: Router, private telemetryService: TelemetryService, - private i18n: I18n, - private textToDownloadService: TextToDownloadService, private telemetryNotificationService: TelemetryNotificationService - ) {} + ) { + super(); + } ngOnInit() { - this.loading = true; const observables = [ this.mgrModuleService.getOptions('telemetry'), this.mgrModuleService.getConfig('telemetry') @@ -72,14 +71,15 @@ export class TelemetryComponent implements OnInit { this.moduleEnabled = configResp['enabled']; this.sendToUrl = configResp['url']; this.sendToDeviceUrl = configResp['device_url']; + this.showContactInfo = configResp['channel_ident']; this.options = _.pick(resp[0], this.requiredFields); - const configs = _.pick(configResp, this.requiredFields); + this.configResp = _.pick(configResp, this.requiredFields); this.createConfigForm(); - this.configForm.setValue(configs); - this.loading = false; + this.configForm.setValue(this.configResp); + this.loadingReady(); }, (_error) => { - this.error = true; + this.loadingError(); } ); } @@ -92,9 +92,71 @@ export class TelemetryComponent implements OnInit { this.configForm = this.formBuilder.group(controlsConfig); } + private replacer(key: string, value: any) { + // Display the arrays of keys 'ranges' and 'values' horizontally as they take up too much space + // and Stringify displays it in vertical by default. + if ((key === 'ranges' || key === 'values') && Array.isArray(value)) { + const elements = []; + for (let i = 0; i < value.length; i++) { + elements.push(JSON.stringify(value[i])); + } + return elements; + } + // Else, just return the value as is, without any formatting. + return value; + } + + replacerTest(report: object) { + return JSON.stringify(report, this.replacer, 2); + } + + private formatReport() { + let copy = {}; + copy = JSON.parse(JSON.stringify(this.report)); + const perf_keys = [ + 'perf_counters', + 'stats_per_pool', + 'stats_per_pg', + 'io_rate', + 'osd_perf_histograms', + 'mempool', + 'heap_stats', + 'rocksdb_stats' + ]; + for (let i = 0; i < perf_keys.length; i++) { + const key = perf_keys[i]; + if (key in copy['report']) { + delete copy['report'][key]; + } + } + return JSON.stringify(copy, null, 2); + } + + formatReportTest(report: object) { + let copy = {}; + copy = JSON.parse(JSON.stringify(report)); + const perf_keys = [ + 'perf_counters', + 'stats_per_pool', + 'stats_per_pg', + 'io_rate', + 'osd_perf_histograms', + 'mempool', + 'heap_stats', + 'rocksdb_stats' + ]; + for (let i = 0; i < perf_keys.length; i++) { + const key = perf_keys[i]; + if (key in copy) { + delete copy[key]; + } + } + return JSON.stringify(copy, null, 2); + } + private createPreviewForm() { const controls = { - report: JSON.stringify(this.report, null, 2), + report: this.formatReport(), reportId: this.reportId, licenseAgrmt: [this.licenseAgrmt, Validators.requiredTrue] }; @@ -105,14 +167,7 @@ export class TelemetryComponent implements OnInit { const result = []; switch (option.type) { case 'int': - result.push(CdValidators.number()); result.push(Validators.required); - if (_.isNumber(option.min)) { - result.push(Validators.min(option.min)); - } - if (_.isNumber(option.max)) { - result.push(Validators.max(option.max)); - } break; case 'str': if (_.isNumber(option.min)) { @@ -126,53 +181,64 @@ export class TelemetryComponent implements OnInit { return result; } + private updateReportFromConfig(updatedConfig: Object = {}) { + // update channels + const availableChannels: string[] = this.report['report']['channels_available']; + const updatedChannels = []; + for (const channel of availableChannels) { + const key = `channel_${channel}`; + if (updatedConfig[key]) { + updatedChannels.push(channel); + } + } + this.report['report']['channels'] = updatedChannels; + // update contactInfo + for (const contactInfofield of this.contactInfofields) { + this.report['report'][contactInfofield] = updatedConfig[contactInfofield]; + } + } + private getReport() { - this.loading = true; + this.loadingStart(); + this.telemetryService.getReport().subscribe( (resp: object) => { this.report = resp; this.reportId = resp['report']['report_id']; + this.updateReportFromConfig(this.newConfig); this.createPreviewForm(); - this.loading = false; + this.loadingReady(); this.step++; }, (_error) => { - this.error = true; + this.loadingError(); } ); } - updateConfig() { - const config = {}; - _.forEach(Object.values(this.options), (option) => { + toggleIdent() { + this.showContactInfo = !this.showContactInfo; + } + + buildReport() { + this.newConfig = {}; + for (const option of Object.values(this.options)) { const control = this.configForm.get(option.name); - // Append the option only if the value has been modified. - if (control.dirty && control.valid) { - config[option.name] = control.value; - } - }); - this.mgrModuleService.updateConfig('telemetry', config).subscribe( - () => { - this.disableModule( - this.i18n( - `Your settings have been applied successfully. \ -Due to privacy/legal reasons the Telemetry module is now disabled until you \ -complete the next step and accept the license.` - ), - () => { - this.getReport(); - } - ); - }, - () => { - // Reset the 'Submit' button. + // Append the option only if they are valid + if (control.valid) { + this.newConfig[option.name] = control.value; + } else { this.configForm.setErrors({ cdSubmitButton: true }); + return; } - ); - } - - download(report: object, fileName: string) { - this.textToDownloadService.download(JSON.stringify(report, null, 2), fileName); + } + // reset contact info field if ident channel is off + if (!this.newConfig['channel_ident']) { + for (const contactInfofield of this.contactInfofields) { + this.newConfig[contactInfofield] = ''; + } + } + this.getReport(); } disableModule(message: string = null, followUpFunc: Function = null) { @@ -190,25 +256,52 @@ complete the next step and accept the license.` } next() { - if (this.configForm.pristine) { - this.getReport(); - } else { - this.updateConfig(); - } + this.buildReport(); } back() { this.step--; } - onSubmit() { - this.telemetryService.enable().subscribe(() => { - this.telemetryNotificationService.setVisibility(false); - this.notificationService.show( - NotificationType.success, - this.i18n('The Telemetry module has been configured and activated successfully.') - ); - this.router.navigate(['']); + getChangedConfig() { + const updatedConfig = {}; + _.forEach(this.requiredFields, (configField) => { + if (!_.isEqual(this.configResp[configField], this.newConfig[configField])) { + updatedConfig[configField] = this.newConfig[configField]; + } }); + return updatedConfig; + } + + onSubmit() { + const updatedConfig = this.getChangedConfig(); + const observables = [ + this.telemetryService.enable(), + this.mgrModuleService.updateConfig('telemetry', updatedConfig) + ]; + + observableForkJoin(observables).subscribe( + () => { + this.telemetryNotificationService.setVisibility(false); + this.notificationService.show( + NotificationType.success, + $localize`The Telemetry module has been configured and activated successfully.` + ); + }, + () => { + this.telemetryNotificationService.setVisibility(false); + this.notificationService.show( + NotificationType.error, + $localize`An Error occurred while updating the Telemetry module configuration.\ + Please Try again` + ); + // Reset the 'Update' button. + this.previewForm.setErrors({ cdSubmitButton: true }); + }, + () => { + this.newConfig = {}; + this.router.navigate(['']); + } + ); } }