mirror of
https://github.com/ceph/ceph
synced 2025-03-29 23:09:47 +00:00
Merge pull request #38209 from votdev/issue_44404_placement_column
mgr/dashboard: display placement column in service table Reviewed-by: Avan Thakkar <athakkar@redhat.com> Reviewed-by: Kiefer Chang <kiefer.chang@suse.com> Reviewed-by: Ernesto Puerta <epuertat@redhat.com> Reviewed-by: Nizamudeen A <nia@redhat.com> Reviewed-by: Tatjana Dehler <tdehler@suse.com>
This commit is contained in:
commit
6911e753b4
@ -47,6 +47,7 @@ import { RulesListComponent } from './prometheus/rules-list/rules-list.component
|
||||
import { SilenceFormComponent } from './prometheus/silence-form/silence-form.component';
|
||||
import { SilenceListComponent } from './prometheus/silence-list/silence-list.component';
|
||||
import { SilenceMatcherModalComponent } from './prometheus/silence-matcher-modal/silence-matcher-modal.component';
|
||||
import { PlacementPipe } from './services/placement.pipe';
|
||||
import { ServiceDaemonListComponent } from './services/service-daemon-list/service-daemon-list.component';
|
||||
import { ServiceDetailsComponent } from './services/service-details/service-details.component';
|
||||
import { ServiceFormComponent } from './services/service-form/service-form.component';
|
||||
@ -108,7 +109,8 @@ import { TelemetryComponent } from './telemetry/telemetry.component';
|
||||
TelemetryComponent,
|
||||
PrometheusTabsComponent,
|
||||
ServiceFormComponent,
|
||||
OsdFlagsIndivModalComponent
|
||||
OsdFlagsIndivModalComponent,
|
||||
PlacementPipe
|
||||
]
|
||||
})
|
||||
export class ClusterModule {}
|
||||
|
@ -0,0 +1,78 @@
|
||||
import { PlacementPipe } from './placement.pipe';
|
||||
|
||||
describe('PlacementPipe', () => {
|
||||
const pipe = new PlacementPipe();
|
||||
|
||||
it('create an instance', () => {
|
||||
expect(pipe).toBeTruthy();
|
||||
});
|
||||
|
||||
it('transforms to no spec', () => {
|
||||
expect(pipe.transform(undefined)).toBe('no spec');
|
||||
});
|
||||
|
||||
it('transforms to unmanaged', () => {
|
||||
expect(pipe.transform({ unmanaged: true })).toBe('unmanaged');
|
||||
});
|
||||
|
||||
it('transforms placement (1)', () => {
|
||||
expect(
|
||||
pipe.transform({
|
||||
placement: {
|
||||
hosts: ['mon0']
|
||||
}
|
||||
})
|
||||
).toBe('mon0');
|
||||
});
|
||||
|
||||
it('transforms placement (2)', () => {
|
||||
expect(
|
||||
pipe.transform({
|
||||
placement: {
|
||||
hosts: ['mon0', 'mgr0']
|
||||
}
|
||||
})
|
||||
).toBe('mon0;mgr0');
|
||||
});
|
||||
|
||||
it('transforms placement (3)', () => {
|
||||
expect(
|
||||
pipe.transform({
|
||||
placement: {
|
||||
count: 1
|
||||
}
|
||||
})
|
||||
).toBe('count:1');
|
||||
});
|
||||
|
||||
it('transforms placement (4)', () => {
|
||||
expect(
|
||||
pipe.transform({
|
||||
placement: {
|
||||
label: 'foo'
|
||||
}
|
||||
})
|
||||
).toBe('label:foo');
|
||||
});
|
||||
|
||||
it('transforms placement (5)', () => {
|
||||
expect(
|
||||
pipe.transform({
|
||||
placement: {
|
||||
host_pattern: '*'
|
||||
}
|
||||
})
|
||||
).toBe('*');
|
||||
});
|
||||
|
||||
it('transforms placement (6)', () => {
|
||||
expect(
|
||||
pipe.transform({
|
||||
placement: {
|
||||
count: 2,
|
||||
hosts: ['mon0', 'mgr0']
|
||||
}
|
||||
})
|
||||
).toBe('mon0;mgr0;count:2');
|
||||
});
|
||||
});
|
@ -0,0 +1,41 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
@Pipe({
|
||||
name: 'placement'
|
||||
})
|
||||
export class PlacementPipe implements PipeTransform {
|
||||
/**
|
||||
* Convert the placement configuration into human readable form.
|
||||
* The output is equal to the column 'PLACEMENT' in 'ceph orch ls'.
|
||||
* @param serviceSpec The service specification to process.
|
||||
* @return The placement configuration as human readable string.
|
||||
*/
|
||||
transform(serviceSpec: object | undefined): string {
|
||||
if (_.isUndefined(serviceSpec)) {
|
||||
return $localize`no spec`;
|
||||
}
|
||||
if (_.get(serviceSpec, 'unmanaged', false)) {
|
||||
return $localize`unmanaged`;
|
||||
}
|
||||
const kv: Array<any> = [];
|
||||
const hosts: Array<string> = _.get(serviceSpec, 'placement.hosts');
|
||||
const count: number = _.get(serviceSpec, 'placement.count');
|
||||
const label: string = _.get(serviceSpec, 'placement.label');
|
||||
const hostPattern: string = _.get(serviceSpec, 'placement.host_pattern');
|
||||
if (_.isArray(hosts)) {
|
||||
kv.push(...hosts);
|
||||
}
|
||||
if (_.isNumber(count)) {
|
||||
kv.push($localize`count:${count}`);
|
||||
}
|
||||
if (_.isString(label)) {
|
||||
kv.push($localize`label:${label}`);
|
||||
}
|
||||
if (_.isString(hostPattern)) {
|
||||
kv.push(...hostPattern);
|
||||
}
|
||||
return kv.join(';');
|
||||
}
|
||||
}
|
@ -82,7 +82,10 @@ describe('ServicesComponent', () => {
|
||||
it('should have columns that are sortable', () => {
|
||||
expect(
|
||||
component.columns
|
||||
// Filter the 'Expand/Collapse Row' column.
|
||||
.filter((column) => !(column.cellClass === 'cd-datatable-expand-collapse'))
|
||||
// Filter the 'Placement' column.
|
||||
.filter((column) => !(column.prop === ''))
|
||||
.every((column) => Boolean(column.prop))
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
@ -24,6 +24,7 @@ import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
|
||||
import { ModalService } from '~/app/shared/services/modal.service';
|
||||
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
|
||||
import { URLBuilderService } from '~/app/shared/services/url-builder.service';
|
||||
import { PlacementPipe } from './placement.pipe';
|
||||
|
||||
const BASE_URL = 'services';
|
||||
|
||||
@ -108,6 +109,12 @@ export class ServicesComponent extends ListWithDetails implements OnChanges, OnI
|
||||
length: 12
|
||||
}
|
||||
},
|
||||
{
|
||||
name: $localize`Placement`,
|
||||
prop: '',
|
||||
pipe: new PlacementPipe(),
|
||||
flexGrow: 1
|
||||
},
|
||||
{
|
||||
name: $localize`Running`,
|
||||
prop: 'status.running',
|
||||
|
Loading…
Reference in New Issue
Block a user