]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.html
38f20476207908f961593bc7a98fe47b2250c934
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / block / rbd-form / rbd-form.component.html
1 <div class="cd-col-form"
2 *cdFormLoading="loading">
3 <form name="rbdForm"
4 #formDir="ngForm"
5 [formGroup]="rbdForm"
6 novalidate>
7 <div class="card">
8 <div i18n="form title"
9 class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
10 <div class="card-body">
11
12 <!-- Parent -->
13 <div class="form-group row"
14 *ngIf="rbdForm.getValue('parent')">
15 <label i18n
16 class="cd-col-form-label"
17 for="name">{{ action | titlecase }} from</label>
18 <div class="cd-col-form-input">
19 <input class="form-control"
20 type="text"
21 id="parent"
22 name="parent"
23 formControlName="parent">
24 <hr>
25 </div>
26 </div>
27
28 <!-- Name -->
29 <div class="form-group row">
30 <label class="cd-col-form-label required"
31 for="name"
32 i18n>Name</label>
33 <div class="cd-col-form-input">
34 <input class="form-control"
35 type="text"
36 placeholder="Name..."
37 id="name"
38 name="name"
39 formControlName="name"
40 autofocus>
41 <span class="invalid-feedback"
42 *ngIf="rbdForm.showError('name', formDir, 'required')">
43 <ng-container i18n>This field is required.</ng-container>
44 </span>
45 <span class="invalid-feedback"
46 *ngIf="rbdForm.showError('name', formDir, 'pattern')">
47 <ng-container i18n>'/' and '@' are not allowed.</ng-container>
48 </span>
49 </div>
50 </div>
51
52 <!-- Pool -->
53 <div class="form-group row"
54 (change)="onPoolChange($event.target.value)">
55 <label class="cd-col-form-label"
56 [ngClass]="{'required': mode !== 'editing'}"
57 for="pool"
58 i18n>Pool</label>
59 <div class="cd-col-form-input">
60 <input class="form-control"
61 type="text"
62 placeholder="Pool name..."
63 id="pool"
64 name="pool"
65 formControlName="pool"
66 *ngIf="mode === 'editing' || !poolPermission.read">
67 <select id="pool"
68 name="pool"
69 class="form-control"
70 formControlName="pool"
71 *ngIf="mode !== 'editing' && poolPermission.read"
72 (change)="setPoolMirrorMode()">
73 <option *ngIf="pools === null"
74 [ngValue]="null"
75 i18n>Loading...</option>
76 <option *ngIf="pools !== null && pools.length === 0"
77 [ngValue]="null"
78 i18n>-- No rbd pools available --</option>
79 <option *ngIf="pools !== null && pools.length > 0"
80 [ngValue]="null"
81 i18n>-- Select a pool --</option>
82 <option *ngFor="let pool of pools"
83 [value]="pool.pool_name">{{ pool.pool_name }}</option>
84 </select>
85 <span *ngIf="rbdForm.showError('pool', formDir, 'required')"
86 class="invalid-feedback"
87 i18n>This field is required.</span>
88 </div>
89 </div>
90
91 <!-- Namespace -->
92 <div class="form-group row"
93 *ngIf="mode !== 'editing' && rbdForm.getValue('pool') && namespaces === null">
94 <div class="cd-col-form-offset">
95 <i [ngClass]="[icons.spinner, icons.spin]"></i>
96 </div>
97 </div>
98 <div class="form-group row"
99 *ngIf="(mode === 'editing' && rbdForm.getValue('namespace')) || mode !== 'editing' && (namespaces && namespaces.length > 0 || !poolPermission.read)">
100 <label class="cd-col-form-label"
101 for="pool">
102 Namespace
103 </label>
104 <div class="cd-col-form-input">
105 <input class="form-control"
106 type="text"
107 placeholder="Namespace..."
108 id="namespace"
109 name="namespace"
110 formControlName="namespace"
111 *ngIf="mode === 'editing' || !poolPermission.read">
112 <select id="namespace"
113 name="namespace"
114 class="form-control"
115 formControlName="namespace"
116 *ngIf="mode !== 'editing' && poolPermission.read">
117 <option *ngIf="pools === null"
118 [ngValue]="null"
119 i18n>Loading...</option>
120 <option *ngIf="pools !== null && pools.length === 0"
121 [ngValue]="null"
122 i18n>-- No namespaces available --</option>
123 <option *ngIf="pools !== null && pools.length > 0"
124 [ngValue]="null"
125 i18n>-- Select a namespace --</option>
126 <option *ngFor="let namespace of namespaces"
127 [value]="namespace">{{ namespace }}</option>
128 </select>
129 </div>
130 </div>
131
132 <!-- Use a dedicated pool -->
133 <div class="form-group row">
134 <div class="cd-col-form-offset">
135 <div class="custom-control custom-checkbox">
136 <input type="checkbox"
137 class="custom-control-input"
138 id="useDataPool"
139 name="useDataPool"
140 formControlName="useDataPool"
141 (change)="onUseDataPoolChange()">
142 <label class="custom-control-label"
143 for="useDataPool"
144 i18n>Use a dedicated data pool</label>
145 <cd-helper *ngIf="allDataPools.length <= 1">
146 <span i18n>You need more than one pool with the rbd application label use to use a dedicated data pool.</span>
147 </cd-helper>
148 </div>
149 </div>
150 </div>
151
152 <!-- Data Pool -->
153 <div class="form-group row"
154 *ngIf="rbdForm.getValue('useDataPool')">
155 <label class="cd-col-form-label"
156 for="dataPool">
157 <span [ngClass]="{'required': mode !== 'editing'}"
158 i18n>Data pool</span>
159 <cd-helper i18n-html
160 html="Dedicated pool that stores the object-data of the RBD.">
161 </cd-helper>
162 </label>
163 <div class="cd-col-form-input">
164 <input class="form-control"
165 type="text"
166 placeholder="Data pool name..."
167 id="dataPool"
168 name="dataPool"
169 formControlName="dataPool"
170 *ngIf="mode === 'editing' || !poolPermission.read">
171 <select id="dataPool"
172 name="dataPool"
173 class="form-control"
174 formControlName="dataPool"
175 (change)="onDataPoolChange($event.target.value)"
176 *ngIf="mode !== 'editing' && poolPermission.read">
177 <option *ngIf="dataPools === null"
178 [ngValue]="null"
179 i18n>Loading...</option>
180 <option *ngIf="dataPools !== null && dataPools.length === 0"
181 [ngValue]="null"
182 i18n>-- No data pools available --</option>
183 <option *ngIf="dataPools !== null && dataPools.length > 0"
184 [ngValue]="null">-- Select a data pool --
185 </option>
186 <option *ngFor="let dataPool of dataPools"
187 [value]="dataPool.pool_name">{{ dataPool.pool_name }}</option>
188 </select>
189 <span class="invalid-feedback"
190 *ngIf="rbdForm.showError('dataPool', formDir, 'required')"
191 i18n>This field is required.</span>
192 </div>
193 </div>
194
195 <!-- Size -->
196 <div class="form-group row">
197 <label class="cd-col-form-label required"
198 for="size"
199 i18n>Size</label>
200 <div class="cd-col-form-input">
201 <input id="size"
202 name="size"
203 class="form-control"
204 type="text"
205 formControlName="size"
206 i18n-placeholder
207 placeholder="e.g., 10GiB"
208 defaultUnit="GiB"
209 cdDimlessBinary>
210 <span class="invalid-feedback"
211 *ngIf="rbdForm.showError('size', formDir, 'required')"
212 i18n>This field is required.</span>
213 <span class="invalid-feedback"
214 *ngIf="rbdForm.showError('size', formDir, 'invalidSizeObject')"
215 i18n>You have to increase the size.</span>
216 </div>
217 </div>
218
219 <!-- Features -->
220 <div class="form-group row"
221 formGroupName="features">
222 <label i18n
223 class="cd-col-form-label"
224 for="features">Features</label>
225 <div class="cd-col-form-input">
226 <div class="custom-control custom-checkbox"
227 *ngFor="let feature of featuresList">
228 <input type="checkbox"
229 class="custom-control-input"
230 id="{{ feature.key }}"
231 name="{{ feature.key }}"
232 formControlName="{{ feature.key }}">
233 <label class="custom-control-label"
234 for="{{ feature.key }}">{{ feature.desc }}</label>
235 <cd-helper *ngIf="feature.helperHtml"
236 html="{{ feature.helperHtml }}">
237 </cd-helper>
238 </div>
239 </div>
240 </div>
241
242 <!-- Mirroring -->
243 <div class="form-group row">
244 <div class="cd-col-form-offset">
245 <div class="custom-control custom-checkbox">
246 <input type="checkbox"
247 class="custom-control-input"
248 id="mirroring"
249 name="mirroring"
250 (change)="setMirrorMode()"
251 formControlName="mirroring">
252 <label class="custom-control-label"
253 for="mirroring">Mirroring</label>
254 <cd-helper *ngIf="mirroring === false && this.currentPoolName">
255 <span i18n>You need to enable a <b>mirror mode</b> in the selected pool. Please <a [routerLink]="['/block/mirroring', {outlets: {modal: ['edit', currentPoolName]}}]">click here to select a mode and enable it in this pool.</a></span>
256 </cd-helper>
257 </div>
258 <div *ngIf="mirroring">
259 <div class="custom-control custom-radio ml-2"
260 *ngFor="let option of mirroringOptions">
261 <input type="radio"
262 class="custom-control-input"
263 [id]="option"
264 [value]="option"
265 name="mirroringMode"
266 (change)="setExclusiveLock()"
267 formControlName="mirroringMode"
268 [attr.disabled]="(poolMirrorMode === 'pool' && option === 'snapshot') ? true : null">
269 <label class="custom-control-label"
270 [for]="option">{{ option | titlecase }}</label>
271 <cd-helper *ngIf="poolMirrorMode === 'pool' && option === 'snapshot'">
272 <span i18n>You need to enable <b>image mirror mode</b> in the selected pool. Please <a [routerLink]="['/block/mirroring', {outlets: {modal: ['edit', currentPoolName]}}]">click here to select a mode and enable it in this pool.</a></span>
273 </cd-helper>
274 </div>
275 </div>
276 </div>
277 </div>
278
279 <div class="form-group row"
280 *ngIf="rbdForm.getValue('mirroringMode') === 'snapshot' && mirroring">
281 <label class="cd-col-form-label"
282 i18n>Schedule Interval
283 <cd-helper i18n-html
284 html="Create Mirror-Snapshots automatically on a periodic basis. The interval can be specified in days, hours, or minutes using d, h, m suffix respectively.">
285 </cd-helper></label>
286 <div class="cd-col-form-input">
287 <input id="schedule"
288 name="schedule"
289 class="form-control"
290 type="text"
291 formControlName="schedule"
292 i18n-placeholder
293 placeholder="e.g., 12h or 1d or 10m"
294 [attr.disabled]="(mode === rbdFormMode.editing) ? true : null">
295 </div>
296 </div>
297
298 <!-- Advanced -->
299 <div class="row">
300 <div class="col-sm-12">
301 <a class="float-right margin-right-md"
302 (click)="advancedEnabled = true; false"
303 *ngIf="!advancedEnabled"
304 href=""
305 i18n>Advanced...</a>
306 </div>
307 </div>
308
309 <div [hidden]="!advancedEnabled">
310
311 <legend class="cd-header"
312 i18n>Advanced</legend>
313
314 <div class="col-md-12">
315 <h4 class="cd-header"
316 i18n>Striping</h4>
317
318 <!-- Object Size -->
319 <div class="form-group row">
320 <label i18n
321 class="cd-col-form-label"
322 for="size">Object size<cd-helper>Objects in the Ceph Storage Cluster have a maximum configurable size (e.g., 2MB, 4MB, etc.). The object size should be large enough to accommodate many stripe units, and should be a multiple of the stripe unit.</cd-helper></label>
323 <div class="cd-col-form-input">
324 <select id="obj_size"
325 name="obj_size"
326 class="form-control"
327 formControlName="obj_size">
328 <option *ngFor="let objectSize of objectSizes"
329 [value]="objectSize">{{ objectSize }}</option>
330 </select>
331 </div>
332 </div>
333
334 <!-- stripingUnit -->
335 <div class="form-group row">
336 <label class="cd-col-form-label"
337 [ngClass]="{'required': rbdForm.getValue('stripingCount')}"
338 for="stripingUnit"
339 i18n>Stripe unit<cd-helper>Stripes have a configurable unit size (e.g., 64kb). The Ceph Client divides the data it will write to objects into equally sized stripe units, except for the last stripe unit. A stripe width, should be a fraction of the Object Size so that an object may contain many stripe units.</cd-helper></label>
340 <div class="cd-col-form-input">
341 <select id="stripingUnit"
342 name="stripingUnit"
343 class="form-control"
344 formControlName="stripingUnit">
345 <option i18n
346 [ngValue]="null">-- Select stripe unit --</option>
347 <option *ngFor="let objectSize of objectSizes"
348 [value]="objectSize">{{ objectSize }}</option>
349 </select>
350 <span class="invalid-feedback"
351 *ngIf="rbdForm.showError('stripingUnit', formDir, 'required')"
352 i18n>This field is required because stripe count is defined!</span>
353 <span class="invalid-feedback"
354 *ngIf="rbdForm.showError('stripingUnit', formDir, 'invalidStripingUnit')"
355 i18n>Stripe unit is greater than object size.</span>
356 </div>
357 </div>
358
359 <!-- Stripe Count -->
360 <div class="form-group row">
361 <label class="cd-col-form-label"
362 [ngClass]="{'required': rbdForm.getValue('stripingUnit')}"
363 for="stripingCount"
364 i18n>Stripe count<cd-helper>The Ceph Client writes a sequence of stripe units over a series of objects determined by the stripe count. The series of objects is called an object set. After the Ceph Client writes to the last object in the object set, it returns to the first object in the object set.</cd-helper></label>
365 <div class="cd-col-form-input">
366 <input id="stripingCount"
367 name="stripingCount"
368 formControlName="stripingCount"
369 class="form-control"
370 type="number">
371 <span class="invalid-feedback"
372 *ngIf="rbdForm.showError('stripingCount', formDir, 'required')"
373 i18n>This field is required because stripe unit is defined!</span>
374 <span class="invalid-feedback"
375 *ngIf="rbdForm.showError('stripingCount', formDir, 'min')"
376 i18n>Stripe count must be greater than 0.</span>
377 </div>
378 </div>
379 </div>
380
381 <cd-rbd-configuration-form [form]="rbdForm"
382 [initializeData]="initializeConfigData"
383 (changes)="getDirtyConfigurationValues = $event"></cd-rbd-configuration-form>
384 </div>
385
386 </div>
387 <div class="card-footer">
388 <cd-form-button-panel (submitActionEvent)="submit()"
389 [form]="formDir"
390 [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
391 wrappingClass="text-right"></cd-form-button-panel>
392 </div>
393 </div>
394 </form>
395 </div>