Skip to content

Commit 7838e1e

Browse files
authored
Merge pull request ceph#61588 from rhcs-dashboard/smb-share-form-create
mgr/dashboard: SMB Create Share Reviewed-by: Afreen Misbah <[email protected]>
2 parents 5a45610 + 56c8c51 commit 7838e1e

File tree

16 files changed

+834
-30
lines changed

16 files changed

+834
-30
lines changed

src/pybind/mgr/dashboard/controllers/smb.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@
8484
"cephfs": ({
8585
"volume": (str, "Name of the CephFS file system"),
8686
"path": (str, "Path within the CephFS file system"),
87-
"provider": (str, "Provider of the CephFS share, e.g., 'samba-vfs'")
87+
"provider": (str, "Provider of the CephFS share, e.g., 'samba-vfs'"),
88+
"subvolumegroup": (str, "Subvolume Group in CephFS file system"),
89+
"subvolume": (str, "Subvolume within the CephFS file system"),
8890
}, "Configuration for the CephFS share")
8991
}
9092

@@ -123,6 +125,30 @@
123125

124126
LIST_USERSGROUPS_SCHEMA = [USERSGROUPS_SCHEMA]
125127

128+
SHARE_SCHEMA_RESULTS = {
129+
"results": ([{
130+
"resource": ({
131+
"resource_type": (str, "ceph.smb.share"),
132+
"cluster_id": (str, "Unique identifier for the cluster"),
133+
"share_id": (str, "Unique identifier for the share"),
134+
"intent": (str, "Desired state of the resource, e.g., 'present' or 'removed'"),
135+
"name": (str, "Name of the share"),
136+
"readonly": (bool, "Indicates if the share is read-only"),
137+
"browseable": (bool, "Indicates if the share is browseable"),
138+
"cephfs": ({
139+
"volume": (str, "Name of the CephFS file system"),
140+
"path": (str, "Path within the CephFS file system"),
141+
"subvolumegroup": (str, "Subvolume Group in CephFS file system"),
142+
"subvolume": (str, "Subvolume within the CephFS file system"),
143+
"provider": (str, "Provider of the CephFS share, e.g., 'samba-vfs'")
144+
}, "Configuration for the CephFS share")
145+
}, "Resource details"),
146+
"state": (str, "State of the resource"),
147+
"success": (bool, "Indicates whether the operation was successful")
148+
}], "List of results with resource details"),
149+
"success": (bool, "Overall success status of the operation")
150+
}
151+
126152

127153
def raise_on_failure(func):
128154
@wraps(func)
@@ -238,6 +264,29 @@ def list(self, cluster_id: str = '') -> List[Share]:
238264
[f'{self._resource}.{cluster_id}' if cluster_id else self._resource])
239265
return res['resources'] if 'resources' in res else [res]
240266

267+
@raise_on_failure
268+
@CreatePermission
269+
@EndpointDoc("Create smb share",
270+
parameters={
271+
'share_resource': (str, 'share_resource')
272+
},
273+
responses={201: SHARE_SCHEMA_RESULTS})
274+
def create(self, share_resource: Share) -> Simplified:
275+
"""
276+
Create an smb share
277+
278+
:param share_resource: Dict share data
279+
:return: Returns share resource.
280+
:rtype: Dict[str, Any]
281+
"""
282+
try:
283+
return mgr.remote(
284+
'smb',
285+
'apply_resources',
286+
json.dumps(share_resource)).to_simplified()
287+
except RuntimeError as e:
288+
raise DashboardException(e, component='smb')
289+
241290
@raise_on_failure
242291
@DeletePermission
243292
@EndpointDoc("Remove an smb share",

src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import { MultiClusterListComponent } from './ceph/cluster/multi-cluster/multi-cl
5353
import { MultiClusterDetailsComponent } from './ceph/cluster/multi-cluster/multi-cluster-details/multi-cluster-details.component';
5454
import { SmbClusterFormComponent } from './ceph/smb/smb-cluster-form/smb-cluster-form.component';
5555
import { SmbTabsComponent } from './ceph/smb/smb-tabs/smb-tabs.component';
56+
import { SmbShareFormComponent } from './ceph/smb/smb-share-form/smb-share-form.component';
5657

5758
@Injectable()
5859
export class PerformanceCounterBreadcrumbsResolver extends BreadcrumbsResolver {
@@ -451,6 +452,11 @@ const routes: Routes = [
451452
path: `${URLVerbs.CREATE}`,
452453
component: SmbClusterFormComponent,
453454
data: { breadcrumbs: ActionLabels.CREATE }
455+
},
456+
{
457+
path: `share/${URLVerbs.CREATE}/:clusterId`,
458+
component: SmbShareFormComponent,
459+
data: { breadcrumbs: ActionLabels.CREATE }
454460
}
455461
]
456462
}

src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-form/smb-cluster-form.component.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import {
88
AUTHMODE,
99
CLUSTERING,
1010
PLACEMENT,
11-
RequestModel,
12-
CLUSTER_RESOURCE,
1311
RESOURCE,
1412
DomainSettings,
15-
JoinSource
13+
JoinSource,
14+
CLUSTER_RESOURCE,
15+
ClusterRequestModel
1616
} from '../smb.model';
1717
import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
1818
import { Icons } from '~/app/shared/enum/icons.enum';
@@ -212,7 +212,7 @@ export class SmbClusterFormComponent extends CdForm implements OnInit {
212212
join_sources: joinSourceObj
213213
};
214214

215-
const requestModel: RequestModel = {
215+
const requestModel: ClusterRequestModel = {
216216
cluster_resource: {
217217
resource_type: CLUSTER_RESOURCE,
218218
cluster_id: rawFormValue.cluster_id,

src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-list/smb-cluster-list.component.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,6 @@ export class SmbClusterListComponent extends ListWithDetails implements OnInit {
5454
) {
5555
super();
5656
this.permission = this.authStorageService.getPermissions().smb;
57-
this.tableActions = [
58-
{
59-
permission: 'delete',
60-
icon: Icons.destroy,
61-
click: () => this.removeSMBClusterModal(),
62-
name: this.actionLabels.REMOVE
63-
}
64-
];
6557
}
6658

6759
ngOnInit() {
@@ -85,6 +77,12 @@ export class SmbClusterListComponent extends ListWithDetails implements OnInit {
8577
routerLink: () => this.urlBuilder.getCreate(),
8678

8779
canBePrimary: (selection: CdTableSelection) => !selection.hasSingleSelection
80+
},
81+
{
82+
permission: 'delete',
83+
icon: Icons.destroy,
84+
click: () => this.removeSMBClusterModal(),
85+
name: this.actionLabels.REMOVE
8886
}
8987
];
9088

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
<div cdsCol
2+
[columnNumbers]="{ md: 4 }">
3+
<form name="smbShareForm"
4+
#formDir="ngForm"
5+
[formGroup]="smbShareForm"
6+
novalidate>
7+
<div i18n="form title"
8+
class="form-header">
9+
{{ action | titlecase }} {{ resource | upperFirst }}
10+
</div>
11+
12+
<!-- Share Id -->
13+
<div class="form-item">
14+
<cds-text-label
15+
labelInputID="share_id"
16+
i18n
17+
helperText="Unique share identifier"
18+
i18n-helperText
19+
cdRequiredField="Share Name"
20+
[invalid]="smbShareForm.controls.share_id.invalid && smbShareForm.controls.share_id.dirty"
21+
[invalidText]="shareError"
22+
>Share Name
23+
<input
24+
cdsText
25+
type="text"
26+
id="share_id"
27+
formControlName="share_id"
28+
[invalid]="smbShareForm.controls.share_id.invalid && smbShareForm.controls.share_id.dirty"
29+
/>
30+
</cds-text-label>
31+
<ng-template #shareError>
32+
<span
33+
class="invalid-feedback"
34+
*ngIf="smbShareForm.showError('share_id', formDir, 'required')"
35+
i18n
36+
>This field is required.</span
37+
>
38+
</ng-template>
39+
</div>
40+
41+
<!-- Volume -->
42+
<div class="form-item">
43+
<cds-select
44+
formControlName="volume"
45+
label="Volume"
46+
cdRequiredField="Volume"
47+
id="volume"
48+
(change)="volumeChangeHandler()"
49+
[invalid]="smbShareForm.controls.volume.invalid && smbShareForm.controls.volume.dirty"
50+
[invalidText]="volumeError"
51+
i18n-label>
52+
<option *ngIf="allFsNames?.length === 0"
53+
value=""
54+
i18n>
55+
-- No filesystem available --
56+
</option>
57+
<option *ngIf="allFsNames !== null && allFsNames?.length > 0"
58+
value=""
59+
i18n>
60+
-- Select the filesystem --
61+
</option>
62+
<option *ngFor="let filesystem of allFsNames"
63+
[value]="filesystem.name"
64+
i18n>
65+
{{ filesystem.name }}
66+
</option>
67+
</cds-select>
68+
<ng-template #volumeError>
69+
<span
70+
class="invalid-feedback"
71+
*ngIf="smbShareForm.showError('volume', formDir, 'required')"
72+
i18n
73+
>This field is required.</span
74+
>
75+
</ng-template>
76+
</div>
77+
78+
<div class="form-item"
79+
*ngIf="smbShareForm.getValue('volume')">
80+
<cds-select
81+
formControlName="subvolume_group"
82+
label="Subvolume Group"
83+
id="subvolume_group"
84+
(change)="getSubVol()"
85+
[skeleton]="allsubvolgrps === null"
86+
i18n-label>
87+
<option *ngIf="allsubvolgrps === null"
88+
value=""
89+
i18n>Loading...</option>
90+
<option *ngIf="allsubvolgrps !== null && allsubvolgrps.length >= 0"
91+
value=""
92+
i18n>
93+
-- Select the CephFS subvolume group --
94+
</option>
95+
<option
96+
*ngFor="let subvol_grp of allsubvolgrps"
97+
[value]="subvol_grp.name"
98+
[selected]="subvol_grp.name === smbShareForm.get('subvolume_group').value"
99+
i18n
100+
>
101+
{{ subvol_grp.name }}
102+
</option>
103+
</cds-select>
104+
</div>
105+
106+
<div class="form-group row"
107+
*ngIf="smbShareForm.getValue('volume')">
108+
<cds-select
109+
formControlName="subvolume"
110+
label="Subvolume"
111+
id="subvolume"
112+
(change)="setSubVolPath()"
113+
[skeleton]="allsubvols === null"
114+
>
115+
<option *ngIf="allsubvols === null"
116+
value=""
117+
i18n>Loading...</option>
118+
<option *ngIf="allsubvols !== null && allsubvols.length === 0"
119+
value=""
120+
i18n>
121+
-- No SMB subvolume available --
122+
</option>
123+
<option *ngIf="allsubvols !== null && allsubvols.length > 0"
124+
value=""
125+
i18n>
126+
-- Select the SMB subvolume --
127+
</option>
128+
<option
129+
*ngFor="let subvolume of allsubvols"
130+
[value]="subvolume.name"
131+
[selected]="subvolume.name === smbShareForm.get('subvolume').value"
132+
i18n
133+
>
134+
{{ subvolume.name }}
135+
</option>
136+
</cds-select>
137+
</div>
138+
139+
<!-- Path -->
140+
<div class="form-item form-item-append"
141+
cdsRow>
142+
<div cdsCol>
143+
<cds-text-label labelInputID="prefixedPath"
144+
i18n
145+
helperText="A path is a relative path.">Prefixed Path
146+
<input cdsText
147+
type="text"
148+
id="prefixedPath"
149+
formControlName="prefixedPath" />
150+
</cds-text-label>
151+
</div>
152+
<div cdsCol>
153+
<cds-text-label
154+
labelInputID="inputPath"
155+
i18n
156+
[invalid]="
157+
smbShareForm.controls.inputPath.invalid && smbShareForm.controls.inputPath.dirty
158+
"
159+
[invalidText]="pathError"
160+
helperText="A relative path in a cephFS file system."
161+
cdRequiredField="Path"
162+
>Input Path
163+
<input
164+
cdsText
165+
type="text"
166+
id="inputPath"
167+
formControlName="inputPath"
168+
[invalid]="
169+
smbShareForm.controls.inputPath.invalid && smbShareForm.controls.inputPath.dirty
170+
"
171+
/>
172+
</cds-text-label>
173+
<ng-template #pathError>
174+
<span
175+
class="invalid-feedback"
176+
*ngIf="smbShareForm.showError('inputPath', formDir, 'required')"
177+
i18n
178+
>This field is required.</span
179+
>
180+
<span
181+
class="invalid-feedback"
182+
*ngIf="smbShareForm.showError('inputPath', formDir, 'pattern')"
183+
i18n
184+
>Path need to start with a '/' and can be followed by a word</span
185+
>
186+
</ng-template>
187+
</div>
188+
</div>
189+
190+
<!-- Browseable -->
191+
<div class="form-item">
192+
<cds-checkbox id="browseable"
193+
formControlName="browseable"
194+
i18n>Browseable
195+
<cd-help-text
196+
>If selected the share will be included in share listings visible to
197+
clients.</cd-help-text
198+
>
199+
</cds-checkbox>
200+
</div>
201+
202+
<!-- Readonly -->
203+
<div class="form-item">
204+
<cds-checkbox id="readonly"
205+
formControlName="readonly"
206+
i18n>Readonly
207+
<cd-help-text>If selected no clients are permitted to write to the share.</cd-help-text>
208+
</cds-checkbox>
209+
</div>
210+
<cd-form-button-panel
211+
(submitActionEvent)="submitAction()"
212+
[form]="smbShareForm"
213+
[submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
214+
wrappingClass="text-right"
215+
></cd-form-button-panel>
216+
</form>
217+
</div>

src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-share-form/smb-share-form.component.scss

Whitespace-only changes.

0 commit comments

Comments
 (0)