]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/dashboard: list smb
authorDnyaneshwari <dnyaneshwari@li-9c9fbecc-2d5c-11b2-a85c-e2a7cc8a424f.ibm.com>
Tue, 19 Nov 2024 07:01:52 +0000 (12:31 +0530)
committerDnyaneshwari <dnyaneshwari@li-9c9fbecc-2d5c-11b2-a85c-e2a7cc8a424f.ibm.com>
Mon, 2 Dec 2024 10:22:00 +0000 (15:52 +0530)
Tracker: https://tracker.ceph.com/issues/69080

Signed-off-by: Dnyaneshwari Talwekar <dtalweka@redhat.com>
14 files changed:
src/pybind/mgr/dashboard/frontend/cypress/e2e/ui/navigation.po.ts
src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/ceph.module.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb.model.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb.module.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/api/smb.service.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/api/smb.service.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/models/permission.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/models/permissions.ts

index 89c4c7394d9ff0055e66576fe04d6243fc4f701d..ae0e5b64f25d0178a9c96315cc7930d59179c0b3 100644 (file)
@@ -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' }
       ]
     },
     {
index 99d7bd0e2d87d0262b85616ed1d37f17ac7dfe86..f389b64a454bae79745cc2f146409e006421d108 100644 (file)
@@ -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 }]
           }
         ]
       },
index 47772304b505ffa50bbbd0072c076e9bdb4fa994..d269b6aa912eee3f2404b2f70a9324008cbb7479 100644 (file)
@@ -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 (file)
index 0000000..1a73e58
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..d1c24d1
--- /dev/null
@@ -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 (file)
index 0000000..bf61643
--- /dev/null
@@ -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 (file)
index 0000000..3796d92
--- /dev/null
@@ -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 (file)
index 0000000..7cd237d
--- /dev/null
@@ -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]);
+  }
+}
index 0150896e88304c9095a7f9e2a09157e0f7ad81d8..0bcb5278f917bed0c93b05102bb5cc63ea460285 100644 (file)
         <!-- 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
                             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 (file)
index 0000000..2dcdbdb
--- /dev/null
@@ -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 (file)
index 0000000..4f4ebcb
--- /dev/null
@@ -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`);
+  }
+}
index 213fb416ea5fbb9986b65a9f1e72d99f1ea7ccb8..d1010a3408a15e7aca9936713d1e86d1fd92166e 100644 (file)
@@ -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 }
     });
   });
 });
index 5e9fe4aae47a629aa0444dc67383042984824805..838385d840acfc059d2cf19c86764b4209759a51 100644 (file)
@@ -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']);
   }
 }