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-select"
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-select"
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 mb-1">
207 <select class=
"form-select"
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 <button class=
"btn btn-light"
226 [ngClass]=
"{'active': data.erasureInfo}"
229 (click)=
"data.erasureInfo = !data.erasureInfo">
230 <i [ngClass]=
"[icons.questionCircle]"
231 aria-hidden=
"true"></i>
233 <button class=
"btn btn-light"
236 (click)=
"addErasureCodeProfile()">
237 <i [ngClass]=
"[icons.add]"
238 aria-hidden=
"true"></i>
240 <button class=
"btn btn-light"
243 ngbTooltip=
"This profile can't be deleted as it is in use."
246 #
ecpDeletionBtn=
"ngbTooltip"
247 (click)=
"deleteErasureCodeProfile()">
248 <i [ngClass]=
"[icons.trash]"
249 aria-hidden=
"true"></i>
252 <span class=
"form-text text-muted"
254 *
ngIf=
"data.erasureInfo && form.getValue('erasureProfile')">
256 #
ecpInfoTabs=
"ngbNav"
258 <ng-container ngbNavItem=
"ecp-info">
261 <ng-template ngbNavContent
>
262 <cd-table-key-value [renderObjects]=
"true"
263 [hideKeys]=
"['name']"
264 [data]=
"form.getValue('erasureProfile')"
265 [autoReload]=
"false">
266 </cd-table-key-value>
269 <ng-container ngbNavItem=
"used-by-pools">
271 i18n
>Used by pools
</a>
272 <ng-template ngbNavContent
>
273 <ng-template #ecpIsNotUsed
>
274 <span i18n
>Profile is not in use.
</span>
276 <ul *
ngIf=
"ecpUsage; else ecpIsNotUsed">
277 <li *
ngFor=
"let pool of ecpUsage">
285 <div [ngbNavOutlet]=
"ecpInfoTabs"></div>
290 <!-- Crush ruleset selection -->
291 <div class=
"form-group row"
292 *
ngIf=
"isErasure && !editing">
293 <label class=
"cd-col-form-label"
295 i18n
>Crush ruleset
</label>
296 <div class=
"cd-col-form-input">
297 <span class=
"form-text text-muted"
298 i18n
>A new crush ruleset will be implicitly created.
</span>
301 <div class=
"form-group row"
302 *
ngIf=
"isReplicated || editing">
303 <label class=
"cd-col-form-label"
305 i18n
>Crush ruleset
</label>
306 <div class=
"cd-col-form-input">
307 <ng-template #noRules
>
308 <span class=
"form-text text-muted">
309 <span i18n
>There are no rules.
</span>
312 <div *
ngIf=
"current.rules.length > 0; else noRules">
313 <div class=
"input-group">
314 <select class=
"form-select"
316 formControlName=
"crushRule"
318 <option [ngValue]=
"null"
319 i18n
>-- Select a crush rule --
</option>
320 <option *
ngFor=
"let rule of current.rules"
325 <button class=
"btn btn-light"
326 [ngClass]=
"{'active': data.crushInfo}"
327 id=
"crush-info-button"
329 ngbTooltip=
"Placement and
330 replication strategies or distribution policies that allow to
331 specify how CRUSH places data replicas."
333 (click)=
"data.crushInfo = !data.crushInfo">
334 <i [ngClass]=
"[icons.questionCircle]"
335 aria-hidden=
"true"></i>
337 <button class=
"btn btn-light"
339 *
ngIf=
"isReplicated && !editing"
340 (click)=
"addCrushRule()">
341 <i [ngClass]=
"[icons.add]"
342 aria-hidden=
"true"></i>
344 <button class=
"btn btn-light"
345 *
ngIf=
"isReplicated && !editing"
347 ngbTooltip=
"This rule can't be deleted as it is in use."
350 #
crushDeletionBtn=
"ngbTooltip"
351 (click)=
"deleteCrushRule()">
352 <i [ngClass]=
"[icons.trash]"
353 aria-hidden=
"true"></i>
357 <div class=
"form-text text-muted"
358 id=
"crush-info-block"
359 *
ngIf=
"data.crushInfo && form.getValue('crushRule')">
361 #
crushInfoTabs=
"ngbNav"
363 <ng-container ngbNavItem=
"crush-rule-info">
366 <ng-template ngbNavContent
>
367 <cd-table-key-value [renderObjects]=
"false"
368 [hideKeys]=
"['steps', 'type', 'rule_name']"
369 [data]=
"form.getValue('crushRule')"
370 [autoReload]=
"false">
371 </cd-table-key-value>
374 <ng-container ngbNavItem=
"crush-rule-steps">
377 <ng-template ngbNavContent
>
379 <li *
ngFor=
"let step of form.get('crushRule').value.steps">
380 {{ describeCrushStep(step) }}
385 <ng-container ngbNavItem=
"used-by-pools">
387 i18n
>Used by pools
</a>
388 <ng-template ngbNavContent
>
390 <ng-template #ruleIsNotUsed
>
391 <span i18n
>Rule is not in use.
</span>
393 <ul *
ngIf=
"crushUsage; else ruleIsNotUsed">
394 <li *
ngFor=
"let pool of crushUsage">
402 <div [ngbNavOutlet]=
"crushInfoTabs"></div>
404 <span class=
"invalid-feedback"
405 *
ngIf=
"form.showError('crushRule', formDir, 'required')"
406 i18n
>This field is required!
</span>
407 <span class=
"invalid-feedback"
408 *
ngIf=
"form.showError('crushRule', formDir, 'tooFewOsds')"
409 i18n
>The rule can't be used in the current cluster as it has
410 too few OSDs to meet the minimum required OSD by this rule.
</span>
418 <div *
ngIf=
"info.is_all_bluestore"
419 formGroupName=
"compression">
420 <legend i18n
>Compression
</legend>
422 <!-- Compression Mode -->
423 <div class=
"form-group row">
425 class=
"cd-col-form-label"
426 for=
"mode">Mode
</label>
427 <div class=
"cd-col-form-input">
428 <select class=
"form-select"
431 formControlName=
"mode">
432 <option *
ngFor=
"let mode of info.compression_modes"
439 <div *
ngIf=
"hasCompressionEnabled()">
440 <!-- Compression algorithm selection -->
441 <div class=
"form-group row">
443 class=
"cd-col-form-label"
444 for=
"algorithm">Algorithm
</label>
445 <div class=
"cd-col-form-input">
446 <select class=
"form-select"
449 formControlName=
"algorithm">
450 <option *
ngIf=
"!info.compression_algorithms"
452 i18n
>Loading...
</option>
453 <option *
ngIf=
"info.compression_algorithms && info.compression_algorithms.length === 0"
455 ngValue=
"">-- No erasure compression algorithm available --
</option>
456 <option *
ngFor=
"let algorithm of info.compression_algorithms"
464 <!-- Compression min blob size -->
465 <div class=
"form-group row">
467 class=
"cd-col-form-label"
468 for=
"minBlobSize">Minimum blob size
</label>
469 <div class=
"cd-col-form-input">
470 <input id=
"minBlobSize"
472 formControlName=
"minBlobSize"
477 placeholder=
"e.g., 128KiB"
480 <span class=
"invalid-feedback"
481 *
ngIf=
"form.showError('minBlobSize', formDir, 'min')"
482 i18n
>Value should be greater than
0</span>
483 <span class=
"invalid-feedback"
484 *
ngIf=
"form.showError('minBlobSize', formDir, 'maximum')"
485 i18n
>Value should be less than the maximum blob size
</span>
489 <!-- Compression max blob size -->
490 <div class=
"form-group row">
492 class=
"cd-col-form-label"
493 for=
"maxBlobSize">Maximum blob size
</label>
494 <div class=
"cd-col-form-input">
495 <input id=
"maxBlobSize"
498 formControlName=
"maxBlobSize"
501 placeholder=
"e.g., 512KiB"
504 <span class=
"invalid-feedback"
505 *
ngIf=
"form.showError('maxBlobSize', formDir, 'min')"
506 i18n
>Value should be greater than
0</span>
507 <span class=
"invalid-feedback"
508 *
ngIf=
"form.showError('maxBlobSize', formDir, 'minimum')"
509 i18n
>Value should be greater than the minimum blob size
</span>
513 <!-- Compression ratio -->
514 <div class=
"form-group row">
516 class=
"cd-col-form-label"
517 for=
"ratio">Ratio
</label>
518 <div class=
"cd-col-form-input">
521 formControlName=
"ratio"
528 placeholder=
"Compression ratio">
529 <span class=
"invalid-feedback"
530 *
ngIf=
"form.showError('ratio', formDir, 'min') || form.showError('ratio', formDir, 'max')"
531 i18n
>Value should be between
0.0 and
1.0</span>
540 <legend i18n
>Quotas
</legend>
543 <div class=
"form-group row">
544 <label class=
"cd-col-form-label"
546 <ng-container i18n
>Max bytes
</ng-container>
548 <span i18n
>Leave it blank or specify
0 to disable this quota.
</span>
550 <span i18n
>A valid quota should be greater than
0.
</span>
553 <div class=
"cd-col-form-input">
554 <input class=
"form-control"
558 formControlName=
"max_bytes"
560 placeholder=
"e.g., 10GiB"
567 <div class=
"form-group row">
568 <label class=
"cd-col-form-label"
570 <ng-container i18n
>Max objects
</ng-container>
572 <span i18n
>Leave it blank or specify
0 to disable this quota.
</span>
574 <span i18n
>A valid quota should be greater than
0.
</span>
577 <div class=
"cd-col-form-input">
578 <input class=
"form-control"
583 formControlName=
"max_objects">
584 <span class=
"invalid-feedback"
585 *
ngIf=
"form.showError('max_objects', formDir, 'min')"
586 i18n
>The value should be greater or equal to
0</span>
591 <!-- Pool configuration -->
592 <div [hidden]=
"isErasure || data.applications.selected.indexOf('rbd') === -1">
593 <cd-rbd-configuration-form [form]=
"form"
594 [initializeData]=
"initializeConfigData"
595 (changes)=
"currentConfigurationValues = $event()">
596 </cd-rbd-configuration-form>
599 <div class=
"card-footer">
600 <cd-form-button-panel (submitActionEvent)=
"submit()"
602 [submitText]=
"(action | titlecase) + ' ' + (resource | upperFirst)"
603 wrappingClass=
"text-right"></cd-form-button-panel>