diff options
author | Dnyaneshwari <dnyaneshwari@li-9c9fbecc-2d5c-11b2-a85c-e2a7cc8a424f.ibm.com> | 2024-11-19 08:01:52 +0100 |
---|---|---|
committer | Dnyaneshwari <dnyaneshwari@li-9c9fbecc-2d5c-11b2-a85c-e2a7cc8a424f.ibm.com> | 2024-12-02 11:22:00 +0100 |
commit | 926aedfef1921f32da0c692fceb314a4cf3d6e5e (patch) | |
tree | e01f2ad282e58e75dc863defcd1674a101c7fa14 /src/pybind/mgr/dashboard | |
parent | Merge pull request #60404 from VallariAg/wip-nvmeof-listeners-prometheus-alerts (diff) | |
download | ceph-926aedfef1921f32da0c692fceb314a4cf3d6e5e.tar.xz ceph-926aedfef1921f32da0c692fceb314a4cf3d6e5e.zip |
mgr/dashboard: list smb
Tracker: https://tracker.ceph.com/issues/69080
Signed-off-by: Dnyaneshwari Talwekar <dtalweka@redhat.com>
Diffstat (limited to 'src/pybind/mgr/dashboard')
14 files changed, 271 insertions, 5 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/ui/navigation.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/ui/navigation.po.ts index 89c4c7394d9..ae0e5b64f25 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/ui/navigation.po.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/ui/navigation.po.ts @@ -48,7 +48,8 @@ export class NavigationPageHelper extends PageHelper { menu: 'File', submenus: [ { menu: 'File Systems', component: 'cd-cephfs-list' }, - { menu: 'NFS', component: 'cd-error' } + { menu: 'NFS', component: 'cd-error' }, + { menu: 'SMB', component: 'cd-smb-cluster-list' } ] }, { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts index 99d7bd0e2d8..f389b64a454 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts @@ -51,6 +51,7 @@ import { UpgradeProgressComponent } from './ceph/cluster/upgrade/upgrade-progres import { MultiClusterComponent } from './ceph/cluster/multi-cluster/multi-cluster.component'; import { MultiClusterListComponent } from './ceph/cluster/multi-cluster/multi-cluster-list/multi-cluster-list.component'; import { MultiClusterDetailsComponent } from './ceph/cluster/multi-cluster/multi-cluster-details/multi-cluster-details.component'; +import { SmbClusterListComponent } from './ceph/smb/smb-cluster-list/smb-cluster-list.component'; @Injectable() export class PerformanceCounterBreadcrumbsResolver extends BreadcrumbsResolver { @@ -429,6 +430,13 @@ const routes: Routes = [ data: { breadcrumbs: ActionLabels.EDIT } } ] + }, + { + path: 'smb', + data: { + breadcrumbs: 'File/SMB' + }, + children: [{ path: '', component: SmbClusterListComponent }] } ] }, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/ceph.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/ceph.module.ts index 47772304b50..d269b6aa912 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/ceph.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/ceph.module.ts @@ -7,6 +7,7 @@ import { ClusterModule } from './cluster/cluster.module'; import { DashboardModule } from './dashboard/dashboard.module'; import { NfsModule } from './nfs/nfs.module'; import { PerformanceCounterModule } from './performance-counter/performance-counter.module'; +import { SmbModule } from './smb/smb.module'; @NgModule({ imports: [ @@ -16,6 +17,7 @@ import { PerformanceCounterModule } from './performance-counter/performance-coun PerformanceCounterModule, CephfsModule, NfsModule, + SmbModule, SharedModule ], declarations: [] diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.html new file mode 100644 index 00000000000..1a73e58cdd2 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.html @@ -0,0 +1,15 @@ +<ng-container *ngIf="smbClusters$ | async as smbClusters"> + <cd-table + #table + [data]="smbClusters" + columnMode="flex" + [columns]="columns" + identifier="id" + forceIdentifier="true" + selectionType="single" + [hasDetails]="false" + (setExpandedRow)="setExpandedRow($event)" + (fetchData)="loadSMBCluster($event)" + > + </cd-table> +</ng-container> diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.scss new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.scss diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.spec.ts new file mode 100644 index 00000000000..d1c24d1dbe1 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.spec.ts @@ -0,0 +1,35 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SmbClusterListComponent } from './smb-cluster-list.component'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { SharedModule } from '~/app/shared/shared.module'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { RouterTestingModule } from '@angular/router/testing'; + +import { ToastrModule } from 'ngx-toastr'; + +describe('SmbClusterListComponent', () => { + let component: SmbClusterListComponent; + let fixture: ComponentFixture<SmbClusterListComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + BrowserAnimationsModule, + SharedModule, + HttpClientTestingModule, + ToastrModule.forRoot(), + RouterTestingModule + ], + declarations: [SmbClusterListComponent] + }).compileComponents(); + + fixture = TestBed.createComponent(SmbClusterListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.ts new file mode 100644 index 00000000000..bf61643a0cc --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.ts @@ -0,0 +1,73 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { catchError, switchMap } from 'rxjs/operators'; +import { BehaviorSubject, Observable, of } from 'rxjs'; + +import _ from 'lodash'; + +import { ActionLabelsI18n } from '~/app/shared/constants/app.constants'; +import { TableComponent } from '~/app/shared/datatable/table/table.component'; +import { CdTableAction } from '~/app/shared/models/cd-table-action'; +import { CdTableColumn } from '~/app/shared/models/cd-table-column'; +import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context'; +import { ListWithDetails } from '~/app/shared/classes/list-with-details.class'; +import { Permission } from '~/app/shared/models/permissions'; + +import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; +import { SmbService } from '~/app/shared/api/smb.service'; +import { SMBCluster } from '../smb.model'; + +@Component({ + selector: 'cd-smb-cluster-list', + templateUrl: './smb-cluster-list.component.html', + styleUrls: ['./smb-cluster-list.component.scss'] +}) +export class SmbClusterListComponent extends ListWithDetails implements OnInit { + @ViewChild('table', { static: true }) + table: TableComponent; + columns: CdTableColumn[]; + permission: Permission; + tableActions: CdTableAction[]; + context: CdTableFetchDataContext; + + smbClusters$: Observable<SMBCluster[]>; + subject$ = new BehaviorSubject<SMBCluster[]>([]); + + constructor( + private authStorageService: AuthStorageService, + public actionLabels: ActionLabelsI18n, + private smbService: SmbService + ) { + super(); + this.permission = this.authStorageService.getPermissions().smb; + } + + ngOnInit() { + this.columns = [ + { + name: $localize`Name`, + prop: 'cluster_id', + flexGrow: 2 + }, + { + name: $localize`Authentication Mode`, + prop: 'auth_mode', + flexGrow: 2 + } + ]; + + this.smbClusters$ = this.subject$.pipe( + switchMap(() => + this.smbService.listClusters().pipe( + catchError(() => { + this.context.error(); + return of(null); + }) + ) + ) + ); + } + + loadSMBCluster() { + this.subject$.next([]); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb.model.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb.model.ts new file mode 100644 index 00000000000..3796d924565 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb.model.ts @@ -0,0 +1,28 @@ +import { CephServicePlacement } from '~/app/shared/models/service.interface'; + +export interface SMBCluster { + cluster_id: string; + auth_mode: AuthMode; + intent: string; + domain_settings?: DomainSettings; + user_group_settings?: string[]; + custom_dns?: string[]; + placement?: CephServicePlacement; + clustering?: string; + public_addrs?: PublicAddress; +} + +export interface DomainSettings { + realm?: string; + join_sources_ref?: string[]; +} + +export interface PublicAddress { + address: string; + destination: string; +} + +export interface AuthMode { + user: 'User'; + activeDirectory: 'active-directory'; +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb.module.ts new file mode 100644 index 00000000000..7cd237dd8e0 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb.module.ts @@ -0,0 +1,44 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; + +import { NgbNavModule, NgbTooltipModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap'; + +import { SharedModule } from '~/app/shared/shared.module'; + +import { + ButtonModule, + GridModule, + IconModule, + IconService, + InputModule, + SelectModule +} from 'carbon-components-angular'; + +import Close from '@carbon/icons/es/close/32'; +import { SmbClusterListComponent } from './smb-cluster-list/smb-cluster-list.component'; + +@NgModule({ + imports: [ + ReactiveFormsModule, + RouterModule, + SharedModule, + NgbNavModule, + CommonModule, + NgbTypeaheadModule, + NgbTooltipModule, + GridModule, + SelectModule, + InputModule, + ButtonModule, + IconModule + ], + exports: [SmbClusterListComponent], + declarations: [SmbClusterListComponent] +}) +export class SmbModule { + constructor(private iconService: IconService) { + this.iconService.registerAll([Close]); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html index 0150896e883..0bcb5278f91 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html @@ -240,7 +240,7 @@ <!-- Filesystem --> <cds-sidenav-menu title="File" i18n-title - *ngIf="permissions.nfs.read && enabledFeature.nfs || permissions.cephfs.read && enabledFeature.cephfs" + *ngIf="permissions.nfs.read && enabledFeature.nfs || permissions.cephfs.read && enabledFeature.cephfs || permissions.smb.read" class="tc_menuitem_file"> <svg cdsIcon="file-storage" icon @@ -257,6 +257,12 @@ i18n-title *ngIf="permissions.nfs.read && enabledFeature.nfs" class="tc_submenuitem tc_submenuitem_file_nfs"><span i18n>NFS</span></cds-sidenav-item> + <cds-sidenav-item route="/cephfs/smb" + [useRouter]="true" + title="SMB" + i18n-title + *ngIf="permissions.smb.read" + class="tc_submenuitem tc_submenuitem_file_smb"><span i18n>SMB</span></cds-sidenav-item> </cds-sidenav-menu> <!-- Observability --> <cds-sidenav-menu title="Observability" diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/smb.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/smb.service.spec.ts new file mode 100644 index 00000000000..2dcdbdb6402 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/smb.service.spec.ts @@ -0,0 +1,31 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +import { SmbService } from './smb.service'; +import { configureTestBed } from '~/testing/unit-test-helper'; + +describe('SmbService', () => { + let service: SmbService; + let httpTesting: HttpTestingController; + + configureTestBed({ + providers: [SmbService], + imports: [HttpClientTestingModule] + }); + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(SmbService); + httpTesting = TestBed.inject(HttpTestingController); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should call list', () => { + service.listClusters().subscribe(); + const req = httpTesting.expectOne('api/smb/cluster'); + expect(req.request.method).toBe('GET'); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/smb.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/smb.service.ts new file mode 100644 index 00000000000..4f4ebcb423c --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/smb.service.ts @@ -0,0 +1,18 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { SMBCluster } from '~/app/ceph/smb/smb.model'; + +@Injectable({ + providedIn: 'root' +}) +export class SmbService { + baseURL = 'api/smb'; + + constructor(private http: HttpClient) {} + + listClusters(): Observable<SMBCluster[]> { + return this.http.get<SMBCluster[]>(`${this.baseURL}/cluster`); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/permission.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/permission.spec.ts index 213fb416ea5..d1010a3408a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/permission.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/permission.spec.ts @@ -19,7 +19,8 @@ describe('cd-notification classes', () => { rbdImage: { create: false, delete: false, read: false, update: false }, rbdMirroring: { create: false, delete: false, read: false, update: false }, rgw: { create: false, delete: false, read: false, update: false }, - user: { create: false, delete: false, read: false, update: false } + user: { create: false, delete: false, read: false, update: false }, + smb: { create: false, delete: false, read: false, update: false } }); }); @@ -40,7 +41,8 @@ describe('cd-notification classes', () => { 'rbd-image': ['create', 'read', 'update', 'delete'], 'rbd-mirroring': ['create', 'read', 'update', 'delete'], rgw: ['create', 'read', 'update', 'delete'], - user: ['create', 'read', 'update', 'delete'] + user: ['create', 'read', 'update', 'delete'], + smb: ['create', 'read', 'update', 'delete'] }; expect(new Permissions(fullyGranted)).toEqual({ cephfs: { create: true, delete: true, read: true, update: true }, @@ -59,7 +61,8 @@ describe('cd-notification classes', () => { rbdImage: { create: true, delete: true, read: true, update: true }, rbdMirroring: { create: true, delete: true, read: true, update: true }, rgw: { create: true, delete: true, read: true, update: true }, - user: { create: true, delete: true, read: true, update: true } + user: { create: true, delete: true, read: true, update: true }, + smb: { create: true, delete: true, read: true, update: true } }); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/permissions.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/permissions.ts index 5e9fe4aae47..838385d840a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/permissions.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/permissions.ts @@ -29,6 +29,7 @@ export class Permissions { grafana: Permission; prometheus: Permission; nfs: Permission; + smb: Permission; constructor(serverPermissions: any) { this.hosts = new Permission(serverPermissions['hosts']); @@ -48,5 +49,6 @@ export class Permissions { this.grafana = new Permission(serverPermissions['grafana']); this.prometheus = new Permission(serverPermissions['prometheus']); this.nfs = new Permission(serverPermissions['nfs-ganesha']); + this.smb = new Permission(serverPermissions['smb']); } } |