From: Ivo Almeida Date: Mon, 12 Feb 2024 10:08:09 +0000 (+0000) Subject: mgr/dashboard: added cephfs mount details X-Git-Tag: testing/wip-pdonnell-testing-20240430.123648-reef-debug~236^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=5b70629093118b9218e61bb60258fd3f35927f5f;p=ceph-ci.git mgr/dashboard: added cephfs mount details Fixes: https://tracker.ceph.com/issues/64405 Signed-off-by: Ivo Almeida --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts index 0d55845ab59..87a7fe17bd5 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts @@ -21,6 +21,10 @@ import { ModalService } from '~/app/shared/services/modal.service'; import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service'; import { FinishedTask } from '~/app/shared/models/finished-task'; import { NotificationService } from '~/app/shared/services/notification.service'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { CephfsMountDetailsComponent } from '../cephfs-mount-details/cephfs-mount-details.component'; +import { map, switchMap } from 'rxjs/operators'; +import { HealthService } from '~/app/shared/api/health.service'; const BASE_URL = 'cephfs'; @@ -38,6 +42,7 @@ export class CephfsListComponent extends ListWithDetails implements OnInit { permissions: Permissions; icons = Icons; monAllowPoolDelete = false; + modalRef!: NgbModalRef; constructor( private authStorageService: AuthStorageService, @@ -48,7 +53,8 @@ export class CephfsListComponent extends ListWithDetails implements OnInit { private configurationService: ConfigurationService, private modalService: ModalService, private taskWrapper: TaskWrapperService, - public notificationService: NotificationService + public notificationService: NotificationService, + private healthService: HealthService ) { super(); this.permissions = this.authStorageService.getPermissions(); @@ -89,6 +95,13 @@ export class CephfsListComponent extends ListWithDetails implements OnInit { click: () => this.router.navigate([this.urlBuilder.getEdit(this.selection.first().mdsmap.fs_name)]) }, + { + name: this.actionLabels.ATTACH, + permission: 'read', + icon: Icons.bars, + disable: () => !this.selection?.hasSelection, + click: () => this.showAttachInfo() + }, { permission: 'delete', icon: Icons.destroy, @@ -125,6 +138,30 @@ export class CephfsListComponent extends ListWithDetails implements OnInit { this.selection = selection; } + showAttachInfo() { + const selectedFileSystem = this.selection?.selected?.[0]; + + this.cephfsService + .getFsRootDirectory(selectedFileSystem.id) + .pipe( + switchMap((fsData) => + this.healthService.getClusterFsid().pipe(map((data) => ({ clusterId: data, fs: fsData }))) + ) + ) + .subscribe({ + next: (val) => { + this.modalRef = this.modalService.show(CephfsMountDetailsComponent, { + onSubmit: () => this.modalRef.close(), + mountData: { + fsId: val.clusterId, + fsName: selectedFileSystem?.mdsmap?.fs_name, + rootPath: val.fs['path'] + } + }); + } + }); + } + removeVolumeModal() { const volName = this.selection.first().mdsmap['fs_name']; this.modalService.show(CriticalConfirmationModalComponent, { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.html new file mode 100644 index 00000000000..a8c30afb1eb --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.html @@ -0,0 +1,38 @@ + + + Attach commands + + + + + + + + + diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.spec.ts new file mode 100644 index 00000000000..141ae428bdd --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.spec.ts @@ -0,0 +1,30 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CephfsMountDetailsComponent } from './cephfs-mount-details.component'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { SharedModule } from '~/app/shared/shared.module'; +import { ToastrModule } from 'ngx-toastr'; +import { RouterTestingModule } from '@angular/router/testing'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { configureTestBed } from '~/testing/unit-test-helper'; + +describe('CephfsSnapshotscheduleListComponent', () => { + let component: CephfsMountDetailsComponent; + let fixture: ComponentFixture; + + configureTestBed({ + declarations: [CephfsMountDetailsComponent], + imports: [HttpClientTestingModule, SharedModule, ToastrModule.forRoot(), RouterTestingModule], + providers: [NgbActiveModal] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CephfsMountDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.ts new file mode 100644 index 00000000000..77a3f4afadc --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-mount-details/cephfs-mount-details.component.ts @@ -0,0 +1,37 @@ +import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'cd-cephfs-mount-details', + templateUrl: './cephfs-mount-details.component.html', + styleUrls: ['./cephfs-mount-details.component.scss'] +}) +export class CephfsMountDetailsComponent implements OnInit, OnDestroy { + @ViewChild('mountDetailsTpl', { static: true }) + mountDetailsTpl: any; + onCancel?: Function; + private canceled = false; + private MOUNT_DIRECTORY = ''; + mountData!: Record; + constructor(public activeModal: NgbActiveModal) {} + mount!: string; + fuse!: string; + nfs!: string; + + ngOnInit(): void { + this.mount = `sudo @${this.mountData?.fsId}.${this.mountData?.fsName}=${this.mountData?.rootPath} ${this.MOUNT_DIRECTORY}`; + this.fuse = `sudo ceph-fuse ${this.MOUNT_DIRECTORY} -r ${this.mountData?.rootPath} --client_mds_namespace=${this.mountData?.fsName}`; + this.nfs = `sudo mount -t nfs -o port= :${this.mountData?.rootPath} ${this.MOUNT_DIRECTORY}`; + } + + ngOnDestroy(): void { + if (this.onCancel && this.canceled) { + this.onCancel(); + } + } + + cancel() { + this.canceled = true; + this.activeModal.close(); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-list/cephfs-snapshotschedule-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-list/cephfs-snapshotschedule-list.component.html index f26f63e755a..4142724f7cf 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-list/cephfs-snapshotschedule-list.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-list/cephfs-snapshotschedule-list.component.html @@ -21,14 +21,14 @@ class="fw-bold" [ngbTooltip]="fullpathTpl" triggers="click:blur"> - {{ row.path?.split?.("@")?.[0] | path }} + {{ row.pathForSelection?.split?.("@")?.[0] | path }} @@ -37,19 +37,19 @@ - + {{ row.path?.split?.("@")?.[0] }} + >{{ row.pathForSelection?.split?.("@")?.[0] }} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-list/cephfs-snapshotschedule-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-list/cephfs-snapshotschedule-list.component.ts index 581ee6e2fa3..ecc2036d5dd 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-list/cephfs-snapshotschedule-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-list/cephfs-snapshotschedule-list.component.ts @@ -130,7 +130,11 @@ export class CephfsSnapshotscheduleListComponent } return this.snapshotScheduleService .getSnapshotScheduleList('/', this.fsName) - .pipe(map((list) => list.map((l) => ({ ...l, path: `${l.path}@${l.schedule}` })))); + .pipe( + map((list) => + list.map((l) => ({ ...l, pathForSelection: `${l.path}@${l.schedule}` })) + ) + ); }), shareReplay(1) ) @@ -138,7 +142,8 @@ export class CephfsSnapshotscheduleListComponent ); this.columns = [ - { prop: 'path', name: $localize`Path`, flexGrow: 3, cellTemplate: this.pathTpl }, + { prop: 'pathForSelection', name: $localize`Path`, flexGrow: 3, cellTemplate: this.pathTpl }, + { prop: 'path', isHidden: true }, { prop: 'subvol', name: $localize`Subvolume`, cellTemplate: this.subvolTpl }, { prop: 'scheduleCopy', name: $localize`Repeat interval` }, { prop: 'schedule', isHidden: true }, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-subvolume-list/cephfs-subvolume-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-subvolume-list/cephfs-subvolume-list.component.ts index 92c139f8e5d..58d849c901e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-subvolume-list/cephfs-subvolume-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-subvolume-list/cephfs-subvolume-list.component.ts @@ -31,6 +31,8 @@ import { CdForm } from '~/app/shared/forms/cd-form'; import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component'; import { CephfsSubvolumeGroupService } from '~/app/shared/api/cephfs-subvolume-group.service'; import { CephfsSubvolumeGroup } from '~/app/shared/models/cephfs-subvolume-group.model'; +import { CephfsMountDetailsComponent } from '../cephfs-mount-details/cephfs-mount-details.component'; +import { HealthService } from '~/app/shared/api/health.service'; @Component({ selector: 'cd-cephfs-subvolume-list', @@ -86,7 +88,8 @@ export class CephfsSubvolumeListComponent extends CdForm implements OnInit, OnCh private modalService: ModalService, private authStorageService: AuthStorageService, private taskWrapper: TaskWrapperService, - private cephfsSubvolumeGroupService: CephfsSubvolumeGroupService + private cephfsSubvolumeGroupService: CephfsSubvolumeGroupService, + private healthService: HealthService ) { super(); this.permissions = this.authStorageService.getPermissions(); @@ -149,6 +152,13 @@ export class CephfsSubvolumeListComponent extends CdForm implements OnInit, OnCh icon: Icons.edit, click: () => this.openModal(true) }, + { + name: this.actionLabels.ATTACH, + permission: 'read', + icon: Icons.bars, + disable: () => !this.selection?.hasSelection, + click: () => this.showAttachInfo() + }, { name: this.actionLabels.REMOVE, permission: 'delete', @@ -188,6 +198,23 @@ export class CephfsSubvolumeListComponent extends CdForm implements OnInit, OnCh this.selection = selection; } + showAttachInfo() { + const selectedSubVolume = this.selection?.selected?.[0]; + + this.healthService.getClusterFsid().subscribe({ + next: (clusterId: string) => { + this.modalRef = this.modalService.show(CephfsMountDetailsComponent, { + onSubmit: () => this.modalRef.close(), + mountData: { + fsId: clusterId, + fsName: this.fsName, + rootPath: selectedSubVolume.info.path + } + }); + } + }); + } + openModal(edit = false) { this.modalService.show( CephfsSubvolumeFormComponent, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs.module.ts index 687dd0b93ee..14481d83822 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs.module.ts @@ -30,6 +30,7 @@ import { CephfsSnapshotscheduleListComponent } from './cephfs-snapshotschedule-l import { DataTableModule } from '../../shared/datatable/datatable.module'; import { CephfsSubvolumeSnapshotsFormComponent } from './cephfs-subvolume-snapshots-list/cephfs-subvolume-snapshots-form/cephfs-subvolume-snapshots-form.component'; import { CephfsSnapshotscheduleFormComponent } from './cephfs-snapshotschedule-form/cephfs-snapshotschedule-form.component'; +import { CephfsMountDetailsComponent } from './cephfs-mount-details/cephfs-mount-details.component'; @NgModule({ imports: [ @@ -64,7 +65,8 @@ import { CephfsSnapshotscheduleFormComponent } from './cephfs-snapshotschedule-f CephfsSubvolumeSnapshotsListComponent, CephfsSnapshotscheduleListComponent, CephfsSnapshotscheduleFormComponent, - CephfsSubvolumeSnapshotsFormComponent + CephfsSubvolumeSnapshotsFormComponent, + CephfsMountDetailsComponent ] }) export class CephfsModule {} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs.service.ts index d2dfbc0e2a7..ab43343f9ed 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs.service.ts @@ -50,6 +50,10 @@ export class CephfsService { return this.http.get(`${this.baseURL}/${id}/mds_counters`); } + getFsRootDirectory(id: string) { + return this.http.get(`${this.baseURL}/${id}/get_root_directory`); + } + mkSnapshot(id: number, path: string, name?: string) { let params = new HttpParams(); params = params.append('path', path); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.html new file mode 100644 index 00000000000..47eac6364e4 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.html @@ -0,0 +1,21 @@ + +
+    
+      {{code}}
+      
+    
+  
+
+ + +
+    {{codes}}
+    
+  
+
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.scss new file mode 100644 index 00000000000..d22855f7519 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.scss @@ -0,0 +1,4 @@ +pre { + background-color: var(--gray-200); + border-radius: 0.5rem; +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.spect.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.spect.ts new file mode 100644 index 00000000000..bc5ad428fd8 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.spect.ts @@ -0,0 +1,38 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CodeBlockComponent } from './code-block.component'; +import { configureTestBed } from '~/testing/unit-test-helper'; + +describe('CodeBlockComponent', () => { + let component: CodeBlockComponent; + let fixture: ComponentFixture; + + configureTestBed({ + declarations: [CodeBlockComponent] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CodeBlockComponent); + component = fixture.componentInstance; + component.codes = []; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should show single codeblock if there are only one code', () => { + component.codes = ['code']; + fixture.detectChanges(); + expect(fixture.nativeElement.querySelector('#singleCodeBlock')).not.toBeNull(); + expect(fixture.nativeElement.querySelector('#bigCodeBlock')).toBeNull(); + }); + + it('should show single codeblock if there are only one code', () => { + component.codes = ['code1', 'code2']; + fixture.detectChanges(); + expect(fixture.nativeElement.querySelector('#bigCodeBlock')).not.toBeNull(); + expect(fixture.nativeElement.querySelector('#singleCodeBlock')).toBeNull(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.ts new file mode 100644 index 00000000000..1021b8c9757 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/code-block/code-block.component.ts @@ -0,0 +1,17 @@ +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'cd-code-block', + templateUrl: './code-block.component.html', + styleUrls: ['./code-block.component.scss'] +}) +export class CodeBlockComponent { + @Input() + codes: string[]; + + @Input() + textWrap: boolean = false; + + @Input() + grayBg: boolean = false; +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts index c312cbabfca..5b533f1cddb 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts @@ -51,6 +51,7 @@ import { UsageBarComponent } from './usage-bar/usage-bar.component'; import { WizardComponent } from './wizard/wizard.component'; import { CardComponent } from './card/card.component'; import { CardRowComponent } from './card-row/card-row.component'; +import { CodeBlockComponent } from './code-block/code-block.component'; import { VerticalNavigationComponent } from './vertical-navigation/vertical-navigation.component'; @NgModule({ @@ -107,6 +108,7 @@ import { VerticalNavigationComponent } from './vertical-navigation/vertical-navi ColorClassFromTextPipe, CardComponent, CardRowComponent, + CodeBlockComponent, VerticalNavigationComponent ], providers: [], @@ -140,6 +142,7 @@ import { VerticalNavigationComponent } from './vertical-navigation/vertical-navi CdLabelComponent, CardComponent, CardRowComponent, + CodeBlockComponent, VerticalNavigationComponent ] }) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.ts index 80c7acbf28a..b6b8ca77e8a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.ts @@ -26,7 +26,7 @@ export class Copy2ClipboardButtonComponent { private getText(): string { const element = document.getElementById(this.source) as HTMLInputElement; - return element.value; + return element?.value || element?.textContent; } @HostListener('click') diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts index 203c2b05d4f..4ef88170aaf 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts @@ -143,6 +143,7 @@ export class ActionLabelsI18n { START_UPGRADE: string; ACTIVATE: string; DEACTIVATE: string; + ATTACH: string; constructor() { /* Create a new item */ @@ -223,6 +224,8 @@ export class ActionLabelsI18n { this.ACTIVATE = $localize`Activate`; this.DEACTIVATE = $localize`Deactivate`; + + this.ATTACH = $localize`Attach`; } } diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index 8d095d86c4e..135379b127b 100644 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -3086,6 +3086,60 @@ paths: - jwt: [] tags: - Cephfs + /api/cephfs/{fs_id}/statfs: + get: + description: "\n Get the statfs of the specified path.\n :param\ + \ fs_id: The filesystem identifier.\n :param path: The path of the\ + \ directory/file.\n :return: Returns a dictionary containing 'bytes',\n\ + \ 'files' and 'subdirs'.\n :rtype: dict\n " + parameters: + - description: File System Identifier + in: path + name: fs_id + required: true + schema: + type: string + - description: File System Path + in: query + name: path + required: true + schema: + type: string + responses: + '200': + content: + application/vnd.ceph.api.v1.0+json: + schema: + properties: + bytes: + description: '' + type: integer + files: + description: '' + type: integer + subdirs: + description: '' + type: integer + required: + - bytes + - files + - subdirs + type: object + description: OK + '400': + description: Operation exception. Please check the response body for details. + '401': + description: Unauthenticated access. Please login first. + '403': + description: Unauthorized access. Please check your permissions. + '500': + description: Unexpected error. Please check the response body for the stack + trace. + security: + - jwt: [] + summary: Get Cephfs statfs of the specified path + tags: + - Cephfs /api/cephfs/{fs_id}/tree: delete: description: "\n Remove a directory.\n :param fs_id: The filesystem\ @@ -3168,6 +3222,95 @@ paths: - jwt: [] tags: - Cephfs + /api/cephfs/{fs_id}/unlink: + delete: + description: "\n Removes a file, link, or symbolic link.\n :param\ + \ fs_id: The filesystem identifier.\n :param path: The path of the\ + \ file or link to unlink.\n " + parameters: + - in: path + name: fs_id + required: true + schema: + type: string + - in: query + name: path + required: true + schema: + type: string + responses: + '202': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: Operation is still executing. Please check the task queue. + '204': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: Resource deleted. + '400': + description: Operation exception. Please check the response body for details. + '401': + description: Unauthenticated access. Please login first. + '403': + description: Unauthorized access. Please check your permissions. + '500': + description: Unexpected error. Please check the response body for the stack + trace. + security: + - jwt: [] + tags: + - Cephfs + /api/cephfs/{fs_id}/write_to_file: + post: + description: "\n Write some data to the specified path.\n :param\ + \ fs_id: The filesystem identifier.\n :param path: The path of the\ + \ file to write.\n :param buf: The str to write to the buf.\n \ + \ " + parameters: + - in: path + name: fs_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + properties: + buf: + type: string + path: + type: string + required: + - path + - buf + type: object + responses: + '201': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: Resource created. + '202': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: Operation is still executing. Please check the task queue. + '400': + description: Operation exception. Please check the response body for details. + '401': + description: Unauthenticated access. Please login first. + '403': + description: Unauthorized access. Please check your permissions. + '500': + description: Unexpected error. Please check the response body for the stack + trace. + security: + - jwt: [] + tags: + - Cephfs /api/cluster: get: parameters: []