1 <div class=
"cd-col-form"
2 *
cdFormLoading=
"loading">
8 <div i18n=
"form title|Example: Create Pool@@formTitle"
9 class=
"card-header">{{ action | titlecase }} {{ resource | upperFirst }}
</div>
11 <div class=
"card-body">
13 <div class=
"form-group row">
14 <label class=
"cd-col-form-label required"
17 <div class=
"cd-col-form-input">
24 formControlName=
"name"
26 <span class=
"invalid-feedback"
27 *
ngIf=
"form.showError('name', formDir, 'required')"
28 i18n
>This field is required!
</span>
29 <span class=
"invalid-feedback"
30 *
ngIf=
"form.showError('name', formDir, 'uniqueName')"
31 i18n
>The chosen Ceph pool name is already in use.
</span>
32 <span *
ngIf=
"form.showError('name', formDir, 'rbdPool')"
33 class=
"invalid-feedback"
34 i18n
>It's not possible to create an RBD pool with '/' in the name.
35 Please change the name or remove 'rbd' from the applications list.
</span>
36 <span *
ngIf=
"form.showError('name', formDir, 'pattern')"
37 class=
"invalid-feedback"
38 i18n
>Pool name can only contain letters, numbers, '.', '-', '_' or '/'.
</span>
42 <!-- Pool type selection -->
43 <div class=
"form-group row">
44 <label class=
"cd-col-form-label required"
46 i18n
>Pool type
</label>
47 <div class=
"cd-col-form-input">
48 <select class=
"form-control"
50 formControlName=
"poolType"
53 i18n
>-- Select a pool type --
</option>
54 <option *
ngFor=
"let poolType of data.poolTypes"
59 <span class=
"invalid-feedback"
60 *
ngIf=
"form.showError('poolType', formDir, 'required')"
61 i18n
>This field is required!
</span>
65 <div *
ngIf=
"isReplicated || isErasure">
66 <!-- PG Autoscale Mode -->
67 <div class=
"form-group row">
69 class=
"cd-col-form-label"
70 for=
"pgAutoscaleMode">PG Autoscale
</label>
71 <div class=
"cd-col-form-input">
72 <select class=
"form-control"
74 name=
"pgAutoscaleMode"
75 formControlName=
"pgAutoscaleMode">
76 <option *
ngFor=
"let mode of pgAutoscaleModes"
85 <div class=
"form-group row"
86 *
ngIf=
"form.getValue('pgAutoscaleMode') !== 'on'">
87 <label class=
"cd-col-form-label required"
89 i18n
>Placement groups
</label>
90 <div class=
"cd-col-form-input">
91 <input class=
"form-control"
94 formControlName=
"pgNum"
97 (focus)=
"externalPgChange = false"
100 <span class=
"invalid-feedback"
101 *
ngIf=
"form.showError('pgNum', formDir, 'required')"
102 i18n
>This field is required!
</span>
103 <span class=
"invalid-feedback"
104 *
ngIf=
"form.showError('pgNum', formDir, 'min')"
105 i18n
>At least one placement group is needed!
</span>
106 <span class=
"invalid-feedback"
107 *
ngIf=
"form.showError('pgNum', formDir, '34')"
108 i18n
>Your cluster can't handle this many PGs. Please recalculate the PG amount needed.
</span>
109 <span class=
"form-text text-muted">
110 <cd-doc section=
"pgs"
111 docText=
"Calculation help"
112 i18n-docText
></cd-doc>
114 <span class=
"form-text text-muted"
115 *
ngIf=
"externalPgChange"
116 i18n
>The current PGs settings were calculated for you, you
117 should make sure the values suit your needs before submit.
</span>
121 <!-- Replica Size -->
122 <div class=
"form-group row"
123 *
ngIf=
"isReplicated">
124 <label class=
"cd-col-form-label required"
126 i18n
>Replicated size
</label>
127 <div class=
"cd-col-form-input">
128 <input class=
"form-control"
134 formControlName=
"size">
135 <span class=
"invalid-feedback"
136 *
ngIf=
"form.showError('size', formDir)">
137 <ul class=
"list-inline">
138 <li i18n
>Minimum: {{ getMinSize() }}
</li>
139 <li i18n
>Maximum: {{ getMaxSize() }}
</li>
142 <span class=
"invalid-feedback"
143 *
ngIf=
"form.showError('size', formDir)"
144 i18n
>The size specified is out of range. A value from
145 {{ getMinSize() }} to {{ getMaxSize() }} is usable.
</span>
146 <span class=
"text-warning-dark"
147 *
ngIf=
"form.getValue('size') === 1"
148 i18n
>A size of
1 will not create a replication of the
149 object. The 'Replicated size' includes the object itself.
</span>
154 <div class=
"form-group row"
155 *
ngIf=
"info.is_all_bluestore && isErasure">
157 class=
"cd-col-form-label">Flags
</label>
158 <div class=
"cd-col-form-input">
159 <div class=
"custom-control custom-checkbox">
160 <input type=
"checkbox"
161 class=
"custom-control-input"
163 formControlName=
"ecOverwrites">
164 <label class=
"custom-control-label"
166 i18n
>EC Overwrites
</label>
172 <!-- Applications -->
173 <div class=
"form-group row">
175 class=
"cd-col-form-label"
176 for=
"applications">Applications
</label>
177 <div class=
"cd-col-form-input">
178 <cd-select-badges id=
"applications"
179 [customBadges]=
"true"
180 [customBadgeValidators]=
"data.applications.validators"
181 [messages]=
"data.applications.messages"
182 [data]=
"data.applications.selected"
183 [options]=
"data.applications.available"
185 (selection)=
"appSelection()">
187 <i *
ngIf=
"data.applications.selected <= 0"
189 title=
"Pools should be associated with an application tag"
190 class=
"{{icons.warning}} icon-warning-color">
195 <div *
ngIf=
"isErasure || isReplicated">
197 <legend i18n
>CRUSH
</legend>
199 <!-- Erasure Profile select -->
200 <div class=
"form-group row"
203 class=
"cd-col-form-label"
204 for=
"erasureProfile">Erasure code profile
</label>
205 <div class=
"cd-col-form-input">
206 <div class=
"input-group">
207 <select class=
"form-control"
209 name=
"erasureProfile"
210 formControlName=
"erasureProfile">
211 <option *
ngIf=
"!ecProfiles"
213 i18n
>Loading...
</option>
214 <option *
ngIf=
"ecProfiles && ecProfiles.length === 0"
216 i18n
>-- No erasure code profile available --
</option>
217 <option *
ngIf=
"ecProfiles && ecProfiles.length > 0"
219 i18n
>-- Select an erasure code profile --
</option>
220 <option *
ngFor=
"let ecp of ecProfiles"
225 <span class=
"input-group-append">
226 <button class=
"btn btn-light"
227 [ngClass]=
"{'active': data.erasureInfo}"
230 (click)=
"data.erasureInfo = !data.erasureInfo">
231 <i [ngClass]=
"[icons.questionCircle]"
232 aria-hidden=
"true"></i>
234 <button class=
"btn btn-light"
237 (click)=
"addErasureCodeProfile()">
238 <i [ngClass]=
"[icons.add]"
239 aria-hidden=
"true"></i>
241 <button class=
"btn btn-light"
244 ngbTooltip=
"This profile can't be deleted as it is in use."
247 #
ecpDeletionBtn=
"ngbTooltip"
248 (click)=
"deleteErasureCodeProfile()">
249 <i [ngClass]=
"[icons.trash]"
250 aria-hidden=
"true"></i>
254 <span class=
"form-text text-muted"
256 *
ngIf=
"data.erasureInfo && form.getValue('erasureProfile')">
258 #
ecpInfoTabs=
"ngbNav"
260 <li ngbNavItem=
"ecp-info">
263 <ng-template ngbNavContent
>
264 <cd-table-key-value [renderObjects]=
"true"
265 [hideKeys]=
"['name']"
266 [data]=
"form.getValue('erasureProfile')"
267 [autoReload]=
"false">
268 </cd-table-key-value>
271 <li ngbNavItem=
"used-by-pools">
273 i18n
>Used by pools
</a>
274 <ng-template ngbNavContent
>
275 <ng-template #ecpIsNotUsed
>
276 <span i18n
>Profile is not in use.
</span>
278 <ul *
ngIf=
"ecpUsage; else ecpIsNotUsed">
279 <li *
ngFor=
"let pool of ecpUsage">
287 <div [ngbNavOutlet]=
"ecpInfoTabs"></div>
292 <!-- Crush ruleset selection -->
293 <div class=
"form-group row"
294 *
ngIf=
"isErasure && !editing">
295 <label class=
"cd-col-form-label"
297 i18n
>Crush ruleset
</label>
298 <div class=
"cd-col-form-input">
299 <span class=
"form-text text-muted"
300 i18n
>A new crush ruleset will be implicitly created.
</span>
303 <div class=
"form-group row"
304 *
ngIf=
"isReplicated || editing">
305 <label class=
"cd-col-form-label"
307 i18n
>Crush ruleset
</label>
308 <div class=
"cd-col-form-input">
309 <ng-template #noRules
>
310 <span class=
"form-text text-muted">
311 <span i18n
>There are no rules.
</span>
314 <div *
ngIf=
"current.rules.length > 0; else noRules">
315 <div class=
"input-group">
316 <select class=
"form-control"
318 formControlName=
"crushRule"
320 <option [ngValue]=
"null"
321 i18n
>-- Select a crush rule --
</option>
322 <option *
ngFor=
"let rule of current.rules"
327 <span class=
"input-group-append">
328 <button class=
"btn btn-light"
329 [ngClass]=
"{'active': data.crushInfo}"
330 id=
"crush-info-button"
332 ngbTooltip=
"Placement and
333 replication strategies or distribution policies that allow to
334 specify how CRUSH places data replicas."
336 (click)=
"data.crushInfo = !data.crushInfo">
337 <i [ngClass]=
"[icons.questionCircle]"
338 aria-hidden=
"true"></i>
340 <button class=
"btn btn-light"
342 *
ngIf=
"isReplicated && !editing"
343 (click)=
"addCrushRule()">
344 <i [ngClass]=
"[icons.add]"
345 aria-hidden=
"true"></i>
347 <button class=
"btn btn-light"
348 *
ngIf=
"isReplicated && !editing"
350 ngbTooltip=
"This rule can't be deleted as it is in use."
353 #
crushDeletionBtn=
"ngbTooltip"
354 (click)=
"deleteCrushRule()">
355 <i [ngClass]=
"[icons.trash]"
356 aria-hidden=
"true"></i>
361 <div class=
"form-text text-muted"
362 id=
"crush-info-block"
363 *
ngIf=
"data.crushInfo && form.getValue('crushRule')">
365 #
crushInfoTabs=
"ngbNav"
367 <li ngbNavItem=
"crush-rule-info">
370 <ng-template ngbNavContent
>
371 <cd-table-key-value [renderObjects]=
"false"
372 [hideKeys]=
"['steps', 'type', 'rule_name']"
373 [data]=
"form.getValue('crushRule')"
374 [autoReload]=
"false">
375 </cd-table-key-value>
378 <li ngbNavItem=
"crush-rule-steps">
381 <ng-template ngbNavContent
>
383 <li *
ngFor=
"let step of form.get('crushRule').value.steps">
384 {{ describeCrushStep(step) }}
389 <li ngbNavItem=
"used-by-pools">
391 i18n
>Used by pools
</a>
392 <ng-template ngbNavContent
>
394 <ng-template #ruleIsNotUsed
>
395 <span i18n
>Rule is not in use.
</span>
397 <ul *
ngIf=
"crushUsage; else ruleIsNotUsed">
398 <li *
ngFor=
"let pool of crushUsage">
406 <div [ngbNavOutlet]=
"crushInfoTabs"></div>
408 <span class=
"invalid-feedback"
409 *
ngIf=
"form.showError('crushRule', formDir, 'required')"
410 i18n
>This field is required!
</span>
411 <span class=
"invalid-feedback"
412 *
ngIf=
"form.showError('crushRule', formDir, 'tooFewOsds')"
413 i18n
>The rule can't be used in the current cluster as it has
414 too few OSDs to meet the minimum required OSD by this rule.
</span>
422 <div *
ngIf=
"info.is_all_bluestore"
423 formGroupName=
"compression">
424 <legend i18n
>Compression
</legend>
426 <!-- Compression Mode -->
427 <div class=
"form-group row">
429 class=
"cd-col-form-label"
430 for=
"mode">Mode
</label>
431 <div class=
"cd-col-form-input">
432 <select class=
"form-control"
435 formControlName=
"mode">
436 <option *
ngFor=
"let mode of info.compression_modes"
443 <div *
ngIf=
"hasCompressionEnabled()">
444 <!-- Compression algorithm selection -->
445 <div class=
"form-group row">
447 class=
"cd-col-form-label"
448 for=
"algorithm">Algorithm
</label>
449 <div class=
"cd-col-form-input">
450 <select class=
"form-control"
453 formControlName=
"algorithm">
454 <option *
ngIf=
"!info.compression_algorithms"
456 i18n
>Loading...
</option>
457 <option *
ngIf=
"info.compression_algorithms && info.compression_algorithms.length === 0"
459 ngValue=
"">-- No erasure compression algorithm available --
</option>
460 <option *
ngFor=
"let algorithm of info.compression_algorithms"
468 <!-- Compression min blob size -->
469 <div class=
"form-group row">
471 class=
"cd-col-form-label"
472 for=
"minBlobSize">Minimum blob size
</label>
473 <div class=
"cd-col-form-input">
474 <input id=
"minBlobSize"
476 formControlName=
"minBlobSize"
481 placeholder=
"e.g., 128KiB"
484 <span class=
"invalid-feedback"
485 *
ngIf=
"form.showError('minBlobSize', formDir, 'min')"
486 i18n
>Value should be greater than
0</span>
487 <span class=
"invalid-feedback"
488 *
ngIf=
"form.showError('minBlobSize', formDir, 'maximum')"
489 i18n
>Value should be less than the maximum blob size
</span>
493 <!-- Compression max blob size -->
494 <div class=
"form-group row">
496 class=
"cd-col-form-label"
497 for=
"maxBlobSize">Maximum blob size
</label>
498 <div class=
"cd-col-form-input">
499 <input id=
"maxBlobSize"
502 formControlName=
"maxBlobSize"
505 placeholder=
"e.g., 512KiB"
508 <span class=
"invalid-feedback"
509 *
ngIf=
"form.showError('maxBlobSize', formDir, 'min')"
510 i18n
>Value should be greater than
0</span>
511 <span class=
"invalid-feedback"
512 *
ngIf=
"form.showError('maxBlobSize', formDir, 'minimum')"
513 i18n
>Value should be greater than the minimum blob size
</span>
517 <!-- Compression ratio -->
518 <div class=
"form-group row">
520 class=
"cd-col-form-label"
521 for=
"ratio">Ratio
</label>
522 <div class=
"cd-col-form-input">
525 formControlName=
"ratio"
532 placeholder=
"Compression ratio">
533 <span class=
"invalid-feedback"
534 *
ngIf=
"form.showError('ratio', formDir, 'min') || form.showError('ratio', formDir, 'max')"
535 i18n
>Value should be between
0.0 and
1.0</span>
544 <legend i18n
>Quotas
</legend>
547 <div class=
"form-group row">
548 <label class=
"cd-col-form-label"
550 <ng-container i18n
>Max bytes
</ng-container>
552 <span i18n
>Leave it blank or specify
0 to disable this quota.
</span>
554 <span i18n
>A valid quota should be greater than
0.
</span>
557 <div class=
"cd-col-form-input">
558 <input class=
"form-control"
562 formControlName=
"max_bytes"
564 placeholder=
"e.g., 10GiB"
571 <div class=
"form-group row">
572 <label class=
"cd-col-form-label"
574 <ng-container i18n
>Max objects
</ng-container>
576 <span i18n
>Leave it blank or specify
0 to disable this quota.
</span>
578 <span i18n
>A valid quota should be greater than
0.
</span>
581 <div class=
"cd-col-form-input">
582 <input class=
"form-control"
587 formControlName=
"max_objects">
588 <span class=
"invalid-feedback"
589 *
ngIf=
"form.showError('max_objects', formDir, 'min')"
590 i18n
>The value should be greater or equal to
0</span>
595 <!-- Pool configuration -->
596 <div [hidden]=
"isErasure || data.applications.selected.indexOf('rbd') === -1">
597 <cd-rbd-configuration-form [form]=
"form"
598 [initializeData]=
"initializeConfigData"
599 (changes)=
"currentConfigurationValues = $event()">
600 </cd-rbd-configuration-form>
603 <div class=
"card-footer">
604 <cd-form-button-panel (submitActionEvent)=
"submit()"
606 [submitText]=
"(action | titlecase) + ' ' + (resource | upperFirst)"
607 wrappingClass=
"text-right"></cd-form-button-panel>