except RuntimeError as e:
raise DashboardException(e, component='smb')
+ @DeletePermission
+ @EndpointDoc("Remove an smb cluster",
+ parameters={
+ 'cluster_id': (str, 'Unique identifier for the cluster')},
+ responses={204: None})
+ def delete(self, cluster_id: str):
+ """
+ Remove an smb cluster
+
+ :param cluster_id: Cluster identifier
+ :return: None.
+ """
+ resource = {}
+ resource['resource_type'] = self._resource
+ resource['cluster_id'] = cluster_id
+ resource['intent'] = Intent.REMOVED
+ return mgr.remote('smb', 'apply_resources', json.dumps(resource)).one().to_simplified()
+
@APIRouter('/smb/share', Scope.SMB)
@APIDoc("SMB Share Management API", "SMB")
[hasDetails]="false"
(setExpandedRow)="setExpandedRow($event)"
(fetchData)="loadSMBCluster($event)"
+ (updateSelection)="updateSelection($event)"
>
+ <div class="table-actions">
+ <cd-table-actions
+ class="btn-group"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
+ </cd-table-actions>
+ </div>
</cd-table>
</ng-container>
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
import { SmbService } from '~/app/shared/api/smb.service';
import { SMBCluster } from '../smb.model';
+import { Icons } from '~/app/shared/enum/icons.enum';
+import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
+import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
+import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
+import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
+import { FinishedTask } from '~/app/shared/models/finished-task';
@Component({
selector: 'cd-smb-cluster-list',
permission: Permission;
tableActions: CdTableAction[];
context: CdTableFetchDataContext;
-
smbClusters$: Observable<SMBCluster[]>;
subject$ = new BehaviorSubject<SMBCluster[]>([]);
+ selection = new CdTableSelection();
+ modalRef: NgbModalRef;
constructor(
private authStorageService: AuthStorageService,
public actionLabels: ActionLabelsI18n,
- private smbService: SmbService
+ private smbService: SmbService,
+ private modalService: ModalCdsService,
+ private taskWrapper: TaskWrapperService
) {
super();
this.permission = this.authStorageService.getPermissions().smb;
+ this.tableActions = [
+ {
+ permission: 'delete',
+ icon: Icons.destroy,
+ click: () => this.removeSMBClusterModal(),
+ name: this.actionLabels.REMOVE
+ }
+ ];
}
ngOnInit() {
loadSMBCluster() {
this.subject$.next([]);
}
+
+ updateSelection(selection: CdTableSelection) {
+ this.selection = selection;
+ }
+
+ removeSMBClusterModal() {
+ const cluster_id = this.selection.first().cluster_id;
+
+ this.modalService.show(CriticalConfirmationModalComponent, {
+ itemDescription: $localize`Cluster`,
+ itemNames: [cluster_id],
+ actionDescription: $localize`remove`,
+ submitActionObservable: () =>
+ this.taskWrapper.wrapTaskAroundCall({
+ task: new FinishedTask('smb/cluster/remove', {
+ cluster_id: cluster_id
+ }),
+ call: this.smbService.removeCluster(cluster_id)
+ })
+ });
+ }
}
const req = httpTesting.expectOne('api/smb/cluster');
expect(req.request.method).toBe('GET');
});
+
+ it('should call remove', () => {
+ service.removeCluster('cluster_1').subscribe();
+ const req = httpTesting.expectOne('api/smb/cluster/cluster_1');
+ expect(req.request.method).toBe('DELETE');
+ });
});
listClusters(): Observable<SMBCluster[]> {
return this.http.get<SMBCluster[]>(`${this.baseURL}/cluster`);
}
+
+ removeCluster(clusterId: string) {
+ return this.http.delete(`${this.baseURL}/cluster/${clusterId}`, {
+ observe: 'response'
+ });
+ }
}
'nfs/delete': this.newTaskMessage(this.commonOperations.delete, (metadata) =>
this.nfs(metadata)
),
+ // smb
+ 'smb/cluster/remove': this.newTaskMessage(this.commonOperations.remove, (metadata) =>
+ this.smb(metadata)
+ ),
// Grafana tasks
'grafana/dashboards/update': this.newTaskMessage(
this.commonOperations.update,
}'`;
}
+ smb(metadata: { cluster_id: string }) {
+ return $localize`SMB Cluster '${metadata.cluster_id}'`;
+ }
+
service(metadata: any) {
return $localize`service '${metadata.service_name}'`;
}
tags:
- SMB
/api/smb/cluster/{cluster_id}:
+ delete:
+ description: "\n Remove an smb cluster\n\n :param cluster_id:\
+ \ Cluster identifier\n :return: None.\n "
+ parameters:
+ - description: Unique identifier for the cluster
+ in: path
+ name: cluster_id
+ 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:
+ schema:
+ properties: {}
+ 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: []
+ summary: Remove an smb cluster
+ tags:
+ - SMB
get:
description: "\n Get an smb cluster by cluster id\n "
parameters:
self.assertStatus(201)
self.assertInJsonBody(json.dumps(self._clusters['resources'][1]))
+ def test_remove(self):
+ _res = {
+ "resource": {
+ "resource_type": "ceph.smb.cluster",
+ "cluster_id": "smbRemoveCluster",
+ "intent": "removed"
+ },
+ "state": "removed",
+ "success": "true"
+ }
+ _res_simplified = {
+ "resource_type": "ceph.smb.cluster",
+ "cluster_id": "smbRemoveCluster",
+ "intent": "removed"
+ }
+ mgr.remote = Mock(return_value=Mock(return_value=_res))
+ mgr.remote.return_value.one.return_value.to_simplified = Mock(return_value=_res_simplified)
+ self._delete(f'{self._endpoint}/smbRemoveCluster')
+ self.assertStatus(204)
+ mgr.remote.assert_called_once_with('smb', 'apply_resources', json.dumps(_res_simplified))
+
class SMBShareTest(ControllerTestCase):
_endpoint = '/api/smb/share'