-import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { NvmeofGatewayComponent } from './nvmeof-gateway.component';
import { NvmeofService } from '../../../shared/api/nvmeof.service';
import { HttpClientModule } from '@angular/common/http';
import { SharedModule } from '~/app/shared/shared.module';
+import { ComboBoxModule, GridModule } from 'carbon-components-angular';
+import { NvmeofTabsComponent } from '../nvmeof-tabs/nvmeof-tabs.component';
+import { CephServiceService } from '~/app/shared/api/ceph-service.service';
+
+const mockServiceDaemons = [
+ {
+ daemon_type: 'nvmeof',
+ daemon_id: 'nvmeof.default.ceph-node-01.kdcguk',
+ daemon_name: 'nvmeof.nvmeof.default.ceph-node-01.kdcguk',
+ hostname: 'ceph-node-01',
+ container_id: '6fe5a9ae9c96',
+ container_image_id: '32a3d75b7c146d6c37b04ee3c9ba883ab88a8f7ae8f286de268d0f41ebd86a51',
+ container_image_name: 'quay.io/ceph/nvmeof:1.2.17',
+ container_image_digests: [
+ 'quay.io/ceph/nvmeof@sha256:4308d05d3bb2167fc695d755316fec8d12ec3f00eb7639eeeabad38a5c4df0f9'
+ ],
+ memory_usage: 89443532,
+ cpu_percentage: '98.87%',
+ version: '1.2.17',
+ status: 1,
+ status_desc: 'running'
+ },
+ {
+ daemon_type: 'nvmeof',
+ daemon_id: 'nvmeof.default.ceph-node-02.hybprc',
+ daemon_name: 'nvmeof.nvmeof.default.ceph-node-02.hybprc',
+ hostname: 'ceph-node-02',
+ container_id: '2b061130726b',
+ container_image_id: '32a3d75b7c146d6c37b04ee3c9ba883ab88a8f7ae8f286de268d0f41ebd86a51',
+ container_image_name: 'quay.io/ceph/nvmeof:1.2.17',
+ container_image_digests: [
+ 'quay.io/ceph/nvmeof@sha256:4308d05d3bb2167fc695d755316fec8d12ec3f00eb7639eeeabad38a5c4df0f9'
+ ],
+ memory_usage: 89328189,
+ cpu_percentage: '98.89%',
+ version: '1.2.17',
+ status: 1,
+ status_desc: 'running'
+ }
+];
const mockGateways = [
{
- cli_version: '',
- version: '1.2.5',
- name: 'client.nvmeof.rbd.ceph-node-01.jnmnwa',
- group: '',
- addr: '192.168.100.101',
- port: '5500',
- load_balancing_group: 1,
- spdk_version: '24.01'
+ id: 'client.nvmeof.nvmeof.default.ceph-node-01.kdcguk',
+ hostname: 'ceph-node-01',
+ status_desc: 'running',
+ status: 1
+ },
+ {
+ id: 'client.nvmeof.nvmeof.default.ceph-node-02.hybprc',
+ hostname: 'ceph-node-02',
+ status_desc: 'running',
+ status: 1
+ }
+];
+
+const mockGwGroups = [
+ {
+ content: 'default',
+ serviceName: 'nvmeof.rbd.default'
+ },
+ {
+ content: 'foo',
+ serviceName: 'nvmeof.rbd.foo'
}
];
+const mockServices = [
+ [
+ {
+ service_name: 'nvmeof.rbd.default',
+ service_type: 'nvmeof',
+ unmanaged: false,
+ spec: {
+ group: 'default'
+ }
+ },
+ {
+ service_name: 'nvmeof.rbd.foo',
+ service_type: 'nvmeof',
+ unmanaged: false,
+ spec: {
+ group: 'foo'
+ }
+ }
+ ],
+ 2
+];
class MockNvmeOfService {
- listGateways() {
- return of(mockGateways);
+ listGatewayGroups() {
+ return of(mockServices);
+ }
+}
+
+class MockCephServiceService {
+ getDaemons(_service: string) {
+ return of(mockServiceDaemons);
}
}
let component: NvmeofGatewayComponent;
let fixture: ComponentFixture<NvmeofGatewayComponent>;
- beforeEach(fakeAsync(() => {
- TestBed.configureTestingModule({
- declarations: [NvmeofGatewayComponent],
- imports: [HttpClientModule, SharedModule],
- providers: [{ provide: NvmeofService, useClass: MockNvmeOfService }]
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [NvmeofGatewayComponent, NvmeofTabsComponent],
+ imports: [HttpClientModule, SharedModule, ComboBoxModule, GridModule],
+ providers: [
+ { provide: NvmeofService, useClass: MockNvmeOfService },
+ { provide: CephServiceService, useClass: MockCephServiceService }
+ ]
}).compileComponents();
- }));
- beforeEach(() => {
fixture = TestBed.createComponent(NvmeofGatewayComponent);
component = fixture.componentInstance;
+ component.ngOnInit();
+ fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
- it('should retrieve gateways', fakeAsync(() => {
- component.getGateways();
- tick();
- expect(component.gateways).toEqual(mockGateways);
- }));
+ it('should load gateway groups correctly', () => {
+ expect(component.gwGroups.length).toBe(2);
+ expect(component.gwGroups).toStrictEqual(mockGwGroups);
+ });
+
+ it('should set service name of gateway groups correctly', () => {
+ expect(component.groupService).toBe(mockServices[0][0].service_name);
+ });
+
+ it('should set gateways correctly', () => {
+ expect(component.gateways.length).toBe(2);
+ expect(component.gateways).toStrictEqual(mockGateways);
+ });
});
-import { Component } from '@angular/core';
+import { Component, TemplateRef, ViewChild } from '@angular/core';
+
+import _ from 'lodash';
import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
-import { NvmeofGateway } from '~/app/shared/models/nvmeof';
import { NvmeofService } from '../../../shared/api/nvmeof.service';
+import { CephServiceSpec } from '~/app/shared/models/service.interface';
+import { CephServiceService } from '~/app/shared/api/ceph-service.service';
+import { Daemon } from '~/app/shared/models/daemon.interface';
+
+type ComboBoxItem = {
+ content: string;
+ serviceName: string;
+ selected?: boolean;
+};
+
+type Gateway = {
+ id: string;
+ hostname: string;
+ status: number;
+ status_desc: string;
+};
@Component({
selector: 'cd-nvmeof-gateway',
styleUrls: ['./nvmeof-gateway.component.scss']
})
export class NvmeofGatewayComponent {
- gateways: NvmeofGateway[] = [];
+ @ViewChild('statusTpl', { static: true })
+ statusTpl: TemplateRef<any>;
+
+ gateways: Gateway[] = [];
gatewayColumns: any;
selection = new CdTableSelection();
+ gwGroups: ComboBoxItem[] = [];
+ groupService: string = null;
- constructor(private nvmeofService: NvmeofService, public actionLabels: ActionLabelsI18n) {}
+ constructor(
+ private nvmeofService: NvmeofService,
+ private cephServiceService: CephServiceService,
+ public actionLabels: ActionLabelsI18n
+ ) {}
ngOnInit() {
+ this.getGatewayGroups();
this.gatewayColumns = [
{
- name: $localize`Name`,
- prop: 'name'
+ name: $localize`Gateway ID`,
+ prop: 'id'
},
{
- name: $localize`Address`,
- prop: 'addr'
+ name: $localize`Host name`,
+ prop: 'hostname'
},
{
- name: $localize`Port`,
- prop: 'port'
+ name: $localize`Status`,
+ prop: 'status_desc',
+ cellTemplate: this.statusTpl
}
];
}
+ // for Status column
+ getStatusClass(row: Gateway): string {
+ return _.get(
+ {
+ '-1': 'badge-danger',
+ '0': 'badge-warning',
+ '1': 'badge-success'
+ },
+ row.status,
+ 'badge-dark'
+ );
+ }
+
+ // Gateways
getGateways() {
- this.nvmeofService.listGateways().subscribe((gateways: NvmeofGateway[] | NvmeofGateway) => {
- if (Array.isArray(gateways)) this.gateways = gateways;
- else this.gateways = [gateways];
+ this.cephServiceService.getDaemons(this.groupService).subscribe((daemons: Daemon[]) => {
+ this.gateways = daemons.length
+ ? daemons.map((daemon: Daemon) => {
+ return {
+ id: `client.${daemon.daemon_name}`,
+ hostname: daemon.hostname,
+ status_desc: daemon.status_desc,
+ status: daemon.status
+ };
+ })
+ : [];
+ });
+ }
+
+ // Gateway groups
+ onGroupSelection(selected: ComboBoxItem) {
+ selected.selected = true;
+ this.groupService = selected.serviceName;
+ this.getGateways();
+ }
+
+ onGroupClear() {
+ this.groupService = null;
+ this.getGateways();
+ }
+
+ getGatewayGroups() {
+ this.nvmeofService.listGatewayGroups().subscribe((response: CephServiceSpec[][]) => {
+ this.gwGroups = response?.[0]?.length
+ ? response[0].map((group: CephServiceSpec) => {
+ return {
+ content: group?.spec?.group,
+ serviceName: group?.service_name
+ };
+ })
+ : [];
+ // Select first group if no group is selected
+ if (!this.groupService && this.gwGroups.length) this.onGroupSelection(this.gwGroups[0]);
});
}
}