}
]
},
+ // NFS
+ {
+ path: 'nfs',
+ canActivate: [AuthGuardService],
+ canActivateChild: [AuthGuardService],
+ data: { breadcrumbs: 'NFS' },
+ children: [
+ { path: '', component: NfsListComponent },
+ { path: 'add', component: NfsFormComponent, data: { breadcrumbs: 'Add' } },
+ {
+ path: 'edit/:cluster_id/:export_id',
+ component: NfsFormComponent,
+ data: { breadcrumbs: 'Edit' }
+ }
+ ]
+ },
// Single Sign-On (SSO)
{ path: 'sso/404', component: SsoNotFoundComponent },
// System
--- /dev/null
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { TestBed } from '@angular/core/testing';
+
+import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper';
+import { NfsService } from './nfs.service';
+
+describe('NfsService', () => {
+ let service: NfsService;
+ let httpTesting: HttpTestingController;
+
+ configureTestBed({
+ providers: [NfsService, i18nProviders],
+ imports: [HttpClientTestingModule]
+ });
+
+ beforeEach(() => {
+ service = TestBed.get(NfsService);
+ httpTesting = TestBed.get(HttpTestingController);
+ });
+
+ afterEach(() => {
+ httpTesting.verify();
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+
+ it('should call list', () => {
+ service.list().subscribe();
+ const req = httpTesting.expectOne('api/nfs-ganesha/export');
+ expect(req.request.method).toBe('GET');
+ });
+
+ it('should call get', () => {
+ service.get('cluster_id', 'export_id').subscribe();
+ const req = httpTesting.expectOne('api/nfs-ganesha/export/cluster_id/export_id');
+ expect(req.request.method).toBe('GET');
+ });
+
+ it('should call create', () => {
+ service.create('foo').subscribe();
+ const req = httpTesting.expectOne('api/nfs-ganesha/export');
+ expect(req.request.method).toBe('POST');
+ expect(req.request.body).toEqual('foo');
+ });
+
+ it('should call update', () => {
+ service.update('cluster_id', 'export_id', 'foo').subscribe();
+ const req = httpTesting.expectOne('api/nfs-ganesha/export/cluster_id/export_id');
+ expect(req.request.body).toEqual('foo');
+ expect(req.request.method).toBe('PUT');
+ });
+
+ it('should call delete', () => {
+ service.delete('hostName', 'exportId').subscribe();
+ const req = httpTesting.expectOne('api/nfs-ganesha/export/hostName/exportId');
+ expect(req.request.method).toBe('DELETE');
+ });
+
+ it('should call lsDir', () => {
+ service.lsDir('foo_dir').subscribe();
+ const req = httpTesting.expectOne('ui-api/nfs-ganesha/lsdir?root_dir=foo_dir');
+ expect(req.request.method).toBe('GET');
+ });
+
+ it('should call buckets', () => {
+ service.buckets('user_foo').subscribe();
+ const req = httpTesting.expectOne('ui-api/nfs-ganesha/rgw/buckets?user_id=user_foo');
+ expect(req.request.method).toBe('GET');
+ });
+
+ it('should call daemon', () => {
+ service.daemon().subscribe();
+ const req = httpTesting.expectOne('api/nfs-ganesha/daemon');
+ expect(req.request.method).toBe('GET');
+ });
+
+ it('should call start', () => {
+ service.start('host_name').subscribe();
+ const req = httpTesting.expectOne('api/nfs-ganesha/service/host_name/start');
+ expect(req.request.method).toBe('PUT');
+ });
+
+ it('should call stop', () => {
+ service.stop('host_name').subscribe();
+ const req = httpTesting.expectOne('api/nfs-ganesha/service/host_name/stop');
+ expect(req.request.method).toBe('PUT');
+ });
+});
--- /dev/null
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+
+import { I18n } from '@ngx-translate/i18n-polyfill';
+
+import { ApiModule } from './api.module';
+
+@Injectable({
+ providedIn: ApiModule
+})
+export class NfsService {
+ apiPath = 'api/nfs-ganesha';
+ uiApiPath = 'ui-api/nfs-ganesha';
+
+ nfsAccessType = [
+ {
+ value: 'RW',
+ help: this.i18n('Allows all operations')
+ },
+ {
+ value: 'RO',
+ help: this.i18n('Allows only operations that do not modify the server')
+ },
+ {
+ value: 'MDONLY',
+ help: this.i18n('Does not allow read or write operations, but allows any other operation')
+ },
+ {
+ value: 'MDONLY_RO',
+ help: this.i18n(
+ 'Does not allow read, write, or any operation that modifies file \
+ attributes or directory content'
+ )
+ },
+ {
+ value: 'NONE',
+ help: this.i18n('Allows no access at all')
+ }
+ ];
+
+ nfsFsal = [
+ {
+ value: 'CEPH',
+ descr: this.i18n('CephFS')
+ },
+ {
+ value: 'RGW',
+ descr: this.i18n('Object Gateway')
+ }
+ ];
+
+ nfsSquash = ['no_root_squash', 'root_id_squash', 'root_squash', 'all_squash'];
+
+ constructor(private http: HttpClient, private i18n: I18n) {}
+
+ list() {
+ return this.http.get(`${this.apiPath}/export`);
+ }
+
+ get(clusterId, exportId) {
+ return this.http.get(`${this.apiPath}/export/${clusterId}/${exportId}`);
+ }
+
+ create(nfs) {
+ return this.http.post(`${this.apiPath}/export`, nfs, { observe: 'response' });
+ }
+
+ update(clusterId, id, nfs) {
+ return this.http.put(`${this.apiPath}/export/${clusterId}/${id}`, nfs, { observe: 'response' });
+ }
+
+ delete(clusterId, exportId) {
+ return this.http.delete(`${this.apiPath}/export/${clusterId}/${exportId}`, {
+ observe: 'response'
+ });
+ }
+
+ lsDir(root_dir) {
+ return this.http.get(`${this.uiApiPath}/lsdir?root_dir=${root_dir}`);
+ }
+
+ buckets(user_id) {
+ return this.http.get(`${this.uiApiPath}/rgw/buckets?user_id=${user_id}`);
+ }
+
+ clients() {
+ return this.http.get(`${this.uiApiPath}/cephx/clients`);
+ }
+
+ fsals() {
+ return this.http.get(`${this.uiApiPath}/fsals`);
+ }
+
+ filesystems() {
+ return this.http.get(`${this.uiApiPath}/cephfs/filesystems`);
+ }
+
+ daemon() {
+ return this.http.get(`${this.apiPath}/daemon`);
+ }
+
+ start(host_name: string) {
+ return this.http.put(`${this.apiPath}/service/${host_name}/start`, null, {
+ observe: 'response'
+ });
+ }
+
+ stop(host_name: string) {
+ return this.http.put(`${this.apiPath}/service/${host_name}/stop`, null, {
+ observe: 'response'
+ });
+ }
+}
log: { create: false, delete: false, read: false, update: false },
manager: { create: false, delete: false, read: false, update: false },
monitor: { create: false, delete: false, read: false, update: false },
+ nfs: { create: false, delete: false, read: false, update: false },
osd: { create: false, delete: false, read: false, update: false },
pool: { create: false, delete: false, read: false, update: false },
prometheus: { create: false, delete: false, read: false, update: false },
log: { create: true, delete: true, read: true, update: true },
manager: { create: true, delete: true, read: true, update: true },
monitor: { create: true, delete: true, read: true, update: true },
+ nfs: { create: false, delete: false, read: false, update: false },
osd: { create: true, delete: true, read: true, update: true },
pool: { create: true, delete: true, read: true, update: true },
prometheus: { create: true, delete: true, read: true, update: true },
user: Permission;
grafana: Permission;
prometheus: Permission;
+ nfs: Permission;
constructor(serverPermissions: any) {
this.hosts = new Permission(serverPermissions['hosts']);
this.user = new Permission(serverPermissions['user']);
this.grafana = new Permission(serverPermissions['grafana']);
this.prometheus = new Permission(serverPermissions['prometheus']);
+ this.nfs = new Permission(serverPermissions['nfs-ganesha']);
}
}
),
'iscsi/target/delete': this.newTaskMessage(this.commonOperations.delete, (metadata) =>
this.iscsiTarget(metadata)
+ ),
+ 'nfs/create': this.newTaskMessage(this.commonOperations.create, (metadata) =>
+ this.nfs(metadata)
+ ),
+ 'nfs/edit': this.newTaskMessage(this.commonOperations.update, (metadata) => this.nfs(metadata)),
+ 'nfs/delete': this.newTaskMessage(this.commonOperations.delete, (metadata) =>
+ this.nfs(metadata)
)
};
return this.i18n(`target '{{target_iqn}}'`, { target_iqn: metadata.target_iqn });
}
+ nfs(metadata) {
+ return this.i18n(`NFS {{nfs_id}}`, {
+ nfs_id: `'${metadata.cluster_id}:${metadata.export_id ? metadata.export_id : metadata.path}'`
+ });
+ }
+
_getTaskTitle(task: Task) {
return this.messages[task.name] || this.defaultMessage;
}